<commit_before>// Scintilla source code edit control
/** @file PerLine.cxx
 ** Manages data associated with each line of the document
 **/
// Copyright 1998-2009 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "SplitVector.h"
#include "Partitioning.h"
#include "CellBuffer.h"
#include "PerLine.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

MarkerHandleSet::MarkerHandleSet() {
	root = 0;
}

MarkerHandleSet::~MarkerHandleSet() {
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		MarkerHandleNumber *mhnToFree = mhn;
		mhn = mhn->next;
		delete mhnToFree;
	}
	root = 0;
}

int MarkerHandleSet::Length() const {
	int c = 0;
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		c++;
		mhn = mhn->next;
	}
	return c;
}

int MarkerHandleSet::NumberFromHandle(int handle) const {
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		if (mhn->handle == handle) {
			return mhn->number;
		}
		mhn = mhn->next;
	}
	return - 1;
}

int MarkerHandleSet::MarkValue() const {
	unsigned int m = 0;
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		m |= (1 << mhn->number);
		mhn = mhn->next;
	}
	return m;
}

bool MarkerHandleSet::Contains(int handle) const {
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		if (mhn->handle == handle) {
			return true;
		}
		mhn = mhn->next;
	}
	return false;
}

bool MarkerHandleSet::InsertHandle(int handle, int markerNum) {
	MarkerHandleNumber *mhn = new MarkerHandleNumber;
	if (!mhn)
		return false;
	mhn->handle = handle;
	mhn->number = markerNum;
	mhn->next = root;
	root = mhn;
	return true;
}

void MarkerHandleSet::RemoveHandle(int handle) {
	MarkerHandleNumber **pmhn = &root;
	while (*pmhn) {
		MarkerHandleNumber *mhn = *pmhn;
		if (mhn->handle == handle) {
			*pmhn = mhn->next;
			delete mhn;
			return;
		}
		pmhn = &((*pmhn)->next);
	}
}

bool MarkerHandleSet::RemoveNumber(int markerNum) {
	bool performedDeletion = false;
	MarkerHandleNumber **pmhn = &root;
	while (*pmhn) {
		MarkerHandleNumber *mhn = *pmhn;
		if (mhn->number == markerNum) {
			*pmhn = mhn->next;
			delete mhn;
			performedDeletion = true;
		} else {
			pmhn = &((*pmhn)->next);
		}
	}
	return performedDeletion;
}

void MarkerHandleSet::CombineWith(MarkerHandleSet *other) {
	MarkerHandleNumber **pmhn = &root;
	while (*pmhn) {
		pmhn = &((*pmhn)->next);
	}
	*pmhn = other->root;
	other->root = 0;
}

LineMarkers::~LineMarkers() {
	Init();
}

void LineMarkers::Init() {
	for (int line = 0; line < markers.Length(); line++) {
		delete markers[line];
		markers[line] = 0;
	}
	markers.DeleteAll();
}

void LineMarkers::InsertLine(int line) {
	if (markers.Length()) {
		markers.Insert(line, 0);
	}
}

void LineMarkers::RemoveLine(int line) {
	// Retain the markers from the deleted line by oring them into the previous line
	if (markers.Length()) {
		if (line > 0) {
			MergeMarkers(line - 1);
		}
		markers.Delete(line);
	}
}

int LineMarkers::LineFromHandle(int markerHandle) {
	if (markers.Length()) {
		for (int line = 0; line < markers.Length(); line++) {
			if (markers[line]) {
				if (markers[line]->Contains(markerHandle)) {
					return line;
				}
			}
		}
	}
	return -1;
}

void LineMarkers::MergeMarkers(int pos) {
	if (markers[pos + 1] != NULL) {
		if (markers[pos] == NULL)
			markers[pos] = new MarkerHandleSet;
		markers[pos]->CombineWith(markers[pos + 1]);
		delete markers[pos + 1];
		markers[pos + 1] = NULL;
	}
}

int LineMarkers::MarkValue(int line) {
	if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line])
		return markers[line]->MarkValue();
	else
		return 0;
}

int LineMarkers::AddMark(int line, int markerNum, int lines) {
	handleCurrent++;
	if (!markers.Length()) {
		// No existing markers so allocate one element per line
		markers.InsertValue(0, lines, 0);
	}
	if (!markers[line]) {
		// Need new structure to hold marker handle
		markers[line] = new MarkerHandleSet();
		if (!markers[line])
			return - 1;
	}
	markers[line]->InsertHandle(handleCurrent, markerNum);

	return handleCurrent;
}

void LineMarkers::DeleteMark(int line, int markerNum, bool all) {
	if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) {
		if (markerNum == -1) {
			delete markers[line];
			markers[line] = NULL;
		} else {
			bool performedDeletion = markers[line]->RemoveNumber(markerNum);
			while (all && performedDeletion) {
				performedDeletion = markers[line]->RemoveNumber(markerNum);
			}
			if (markers[line]->Length() == 0) {
				delete markers[line];
				markers[line] = NULL;
			}
		}
	}
}

void LineMarkers::DeleteMarkFromHandle(int markerHandle) {
	int line = LineFromHandle(markerHandle);
	if (line >= 0) {
		markers[line]->RemoveHandle(markerHandle);
		if (markers[line]->Length() == 0) {
			delete markers[line];
			markers[line] = NULL;
		}
	}
}

LineLevels::~LineLevels() {
}

void LineLevels::Init() {
	levels.DeleteAll();
}

void LineLevels::InsertLine(int line) {
	if (levels.Length()) {
		int level = SC_FOLDLEVELBASE;
		if ((line > 0) && (line < levels.Length())) {
			level = levels[line-1] & ~SC_FOLDLEVELWHITEFLAG;
		}
		levels.InsertValue(line, 1, level);
	}
}

void LineLevels::RemoveLine(int line) {
	if (levels.Length()) {
		// Move up following lines but merge header flag from this line
		// to line before to avoid a temporary disappearence causing expansion.
		int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG;
		levels.Delete(line);
		if (line == levels.Length()-1) // Last line loses the header flag
			levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG;
		else if (line > 0)
			levels[line-1] |= firstHeader;
	}
}

void LineLevels::ExpandLevels(int sizeNew) {
	levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE);
}

void LineLevels::ClearLevels() {
	levels.DeleteAll();
}

int LineLevels::SetLevel(int line, int level, int lines) {
	int prev = 0;
	if ((line >= 0) && (line < lines)) {
		if (!levels.Length()) {
			ExpandLevels(lines + 1);
		}
		prev = levels[line];
		if (prev != level) {
			levels[line] = level;
		}
	}
	return prev;
}

int LineLevels::GetLevel(int line) {
	if (levels.Length() && (line >= 0) && (line < levels.Length())) {
		return levels[line];
	} else {
		return SC_FOLDLEVELBASE;
	}
}

LineState::~LineState() {
}

void LineState::Init() {
	lineStates.DeleteAll();
}

void LineState::InsertLine(int line) {
	if (lineStates.Length()) {
		lineStates.EnsureLength(line);
		lineStates.Insert(line, 0);
	}
}

void LineState::RemoveLine(int line) {
	if (lineStates.Length() > line) {
		lineStates.Delete(line);
	}
}

int LineState::SetLineState(int line, int state) {
	lineStates.EnsureLength(line + 1);
	int stateOld = lineStates[line];
	lineStates[line] = state;
	return stateOld;
}

int LineState::GetLineState(int line) {
	lineStates.EnsureLength(line + 1);
	return lineStates[line];
}

int LineState::GetMaxLineState() {
	return lineStates.Length();
}

static int NumberLines(const char *text) {
	if (text) {
		int newLines = 0;
		while (*text) {
			if (*text == '\n')
				newLines++;
			text++;
		}
		return newLines+1;
	} else {
		return 0;
	}
}

// Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
// and then has text and optional styles.

static const int IndividualStyles = 0x100;

struct AnnotationHeader {
	short style;	// Style IndividualStyles implies array of styles
	short lines;
	int length;
};

LineAnnotation::~LineAnnotation() {
	ClearAll();
}

void LineAnnotation::Init() {
	ClearAll();
}

void LineAnnotation::InsertLine(int line) {
	if (annotations.Length()) {
		annotations.Insert(line, 0);
	}
}

void LineAnnotation::RemoveLine(int line) {
	if (annotations.Length() && (line < annotations.Length())) {
		delete []annotations[line];
		annotations.Delete(line);
	}
}

bool LineAnnotation::AnySet() const {
	return annotations.Length() > 0;
}

bool LineAnnotation::MultipleStyles(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return reinterpret_cast<AnnotationHeader *>(annotations[line])->style == IndividualStyles;
	else
		return 0;
}

int LineAnnotation::Style(int line) {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return reinterpret_cast<AnnotationHeader *>(annotations[line])->style;
	else
		return 0;
}

const char *LineAnnotation::Text(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return annotations[line]+sizeof(AnnotationHeader);
	else
		return 0;
}

const unsigned char *LineAnnotation::Styles(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line] && MultipleStyles(line))
		return reinterpret_cast<unsigned char *>(annotations[line] + sizeof(AnnotationHeader) + Length(line));
	else
		return 0;
}

static char *AllocateAnnotation(int length, int style) {
	size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0);
	char *ret = new char[len];
	memset(ret, 0, len);
	return ret;
}

void LineAnnotation::SetText(int line, const char *text) {
	if (text) {
		annotations.EnsureLength(line+1);
		int style = Style(line);
		if (annotations[line]) {
			delete []annotations[line];
		}
		annotations[line] = AllocateAnnotation(strlen(text), style);
		AnnotationHeader *pah = reinterpret_cast<AnnotationHeader*>(annotations[line]);
		pah->style = static_cast<short>(style);
		pah->length = strlen(text);
		pah->lines = static_cast<short>(NumberLines(text));
		memcpy(annotations[line]+sizeof(AnnotationHeader), text, pah->length);
	} else {
		if (annotations.Length() && (line < annotations.Length()) && annotations[line]) {
			delete []annotations[line];
			annotations[line] = 0;
		}
	}
}

void LineAnnotation::ClearAll() {
	for (int line = 0; line < annotations.Length(); line++) {
		delete []annotations[line];
		annotations[line] = 0;
	}
	annotations.DeleteAll();
}

void LineAnnotation::SetStyle(int line, int style) {
	annotations.EnsureLength(line+1);
	if (!annotations[line]) {
		annotations[line] = AllocateAnnotation(0, style);
	}
	reinterpret_cast<AnnotationHeader *>(annotations[line])->style = static_cast<short>(style);
}

void LineAnnotation::SetStyles(int line, const unsigned char *styles) {
	annotations.EnsureLength(line+1);
	if (!annotations[line]) {
		annotations[line] = AllocateAnnotation(0, IndividualStyles);
	} else {
		AnnotationHeader *pahSource = reinterpret_cast<AnnotationHeader *>(annotations[line]);
		if (pahSource->style != IndividualStyles) {
			char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles);
			AnnotationHeader *pahAlloc = reinterpret_cast<AnnotationHeader *>(allocation);
			pahAlloc->length = pahSource->length;
			pahAlloc->lines = pahSource->lines;
			memcpy(allocation + sizeof(AnnotationHeader), annotations[line] + sizeof(AnnotationHeader), pahSource->length);
			delete []annotations[line];
			annotations[line] = allocation;
		}
	}
	AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
	pah->style = IndividualStyles;
	memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length);
}

int LineAnnotation::Length(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return reinterpret_cast<AnnotationHeader *>(annotations[line])->length;
	else
		return 0;
}

int LineAnnotation::Lines(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return reinterpret_cast<AnnotationHeader *>(annotations[line])->lines;
	else
		return 0;
}
<commit_msg>Fixed Bug #2830307 crash when adding marker to line beyond end of document.<commit_after>// Scintilla source code edit control
/** @file PerLine.cxx
 ** Manages data associated with each line of the document
 **/
// Copyright 1998-2009 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "SplitVector.h"
#include "Partitioning.h"
#include "CellBuffer.h"
#include "PerLine.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

MarkerHandleSet::MarkerHandleSet() {
	root = 0;
}

MarkerHandleSet::~MarkerHandleSet() {
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		MarkerHandleNumber *mhnToFree = mhn;
		mhn = mhn->next;
		delete mhnToFree;
	}
	root = 0;
}

int MarkerHandleSet::Length() const {
	int c = 0;
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		c++;
		mhn = mhn->next;
	}
	return c;
}

int MarkerHandleSet::NumberFromHandle(int handle) const {
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		if (mhn->handle == handle) {
			return mhn->number;
		}
		mhn = mhn->next;
	}
	return - 1;
}

int MarkerHandleSet::MarkValue() const {
	unsigned int m = 0;
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		m |= (1 << mhn->number);
		mhn = mhn->next;
	}
	return m;
}

bool MarkerHandleSet::Contains(int handle) const {
	MarkerHandleNumber *mhn = root;
	while (mhn) {
		if (mhn->handle == handle) {
			return true;
		}
		mhn = mhn->next;
	}
	return false;
}

bool MarkerHandleSet::InsertHandle(int handle, int markerNum) {
	MarkerHandleNumber *mhn = new MarkerHandleNumber;
	if (!mhn)
		return false;
	mhn->handle = handle;
	mhn->number = markerNum;
	mhn->next = root;
	root = mhn;
	return true;
}

void MarkerHandleSet::RemoveHandle(int handle) {
	MarkerHandleNumber **pmhn = &root;
	while (*pmhn) {
		MarkerHandleNumber *mhn = *pmhn;
		if (mhn->handle == handle) {
			*pmhn = mhn->next;
			delete mhn;
			return;
		}
		pmhn = &((*pmhn)->next);
	}
}

bool MarkerHandleSet::RemoveNumber(int markerNum) {
	bool performedDeletion = false;
	MarkerHandleNumber **pmhn = &root;
	while (*pmhn) {
		MarkerHandleNumber *mhn = *pmhn;
		if (mhn->number == markerNum) {
			*pmhn = mhn->next;
			delete mhn;
			performedDeletion = true;
		} else {
			pmhn = &((*pmhn)->next);
		}
	}
	return performedDeletion;
}

void MarkerHandleSet::CombineWith(MarkerHandleSet *other) {
	MarkerHandleNumber **pmhn = &root;
	while (*pmhn) {
		pmhn = &((*pmhn)->next);
	}
	*pmhn = other->root;
	other->root = 0;
}

LineMarkers::~LineMarkers() {
	Init();
}

void LineMarkers::Init() {
	for (int line = 0; line < markers.Length(); line++) {
		delete markers[line];
		markers[line] = 0;
	}
	markers.DeleteAll();
}

void LineMarkers::InsertLine(int line) {
	if (markers.Length()) {
		markers.Insert(line, 0);
	}
}

void LineMarkers::RemoveLine(int line) {
	// Retain the markers from the deleted line by oring them into the previous line
	if (markers.Length()) {
		if (line > 0) {
			MergeMarkers(line - 1);
		}
		markers.Delete(line);
	}
}

int LineMarkers::LineFromHandle(int markerHandle) {
	if (markers.Length()) {
		for (int line = 0; line < markers.Length(); line++) {
			if (markers[line]) {
				if (markers[line]->Contains(markerHandle)) {
					return line;
				}
			}
		}
	}
	return -1;
}

void LineMarkers::MergeMarkers(int pos) {
	if (markers[pos + 1] != NULL) {
		if (markers[pos] == NULL)
			markers[pos] = new MarkerHandleSet;
		markers[pos]->CombineWith(markers[pos + 1]);
		delete markers[pos + 1];
		markers[pos + 1] = NULL;
	}
}

int LineMarkers::MarkValue(int line) {
	if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line])
		return markers[line]->MarkValue();
	else
		return 0;
}

int LineMarkers::AddMark(int line, int markerNum, int lines) {
	handleCurrent++;
	if (!markers.Length()) {
		// No existing markers so allocate one element per line
		markers.InsertValue(0, lines, 0);
	}
	if (line >= markers.Length()) {
		return -1;
	}
	if (!markers[line]) {
		// Need new structure to hold marker handle
		markers[line] = new MarkerHandleSet();
		if (!markers[line])
			return -1;
	}
	markers[line]->InsertHandle(handleCurrent, markerNum);

	return handleCurrent;
}

void LineMarkers::DeleteMark(int line, int markerNum, bool all) {
	if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) {
		if (markerNum == -1) {
			delete markers[line];
			markers[line] = NULL;
		} else {
			bool performedDeletion = markers[line]->RemoveNumber(markerNum);
			while (all && performedDeletion) {
				performedDeletion = markers[line]->RemoveNumber(markerNum);
			}
			if (markers[line]->Length() == 0) {
				delete markers[line];
				markers[line] = NULL;
			}
		}
	}
}

void LineMarkers::DeleteMarkFromHandle(int markerHandle) {
	int line = LineFromHandle(markerHandle);
	if (line >= 0) {
		markers[line]->RemoveHandle(markerHandle);
		if (markers[line]->Length() == 0) {
			delete markers[line];
			markers[line] = NULL;
		}
	}
}

LineLevels::~LineLevels() {
}

void LineLevels::Init() {
	levels.DeleteAll();
}

void LineLevels::InsertLine(int line) {
	if (levels.Length()) {
		int level = SC_FOLDLEVELBASE;
		if ((line > 0) && (line < levels.Length())) {
			level = levels[line-1] & ~SC_FOLDLEVELWHITEFLAG;
		}
		levels.InsertValue(line, 1, level);
	}
}

void LineLevels::RemoveLine(int line) {
	if (levels.Length()) {
		// Move up following lines but merge header flag from this line
		// to line before to avoid a temporary disappearence causing expansion.
		int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG;
		levels.Delete(line);
		if (line == levels.Length()-1) // Last line loses the header flag
			levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG;
		else if (line > 0)
			levels[line-1] |= firstHeader;
	}
}

void LineLevels::ExpandLevels(int sizeNew) {
	levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE);
}

void LineLevels::ClearLevels() {
	levels.DeleteAll();
}

int LineLevels::SetLevel(int line, int level, int lines) {
	int prev = 0;
	if ((line >= 0) && (line < lines)) {
		if (!levels.Length()) {
			ExpandLevels(lines + 1);
		}
		prev = levels[line];
		if (prev != level) {
			levels[line] = level;
		}
	}
	return prev;
}

int LineLevels::GetLevel(int line) {
	if (levels.Length() && (line >= 0) && (line < levels.Length())) {
		return levels[line];
	} else {
		return SC_FOLDLEVELBASE;
	}
}

LineState::~LineState() {
}

void LineState::Init() {
	lineStates.DeleteAll();
}

void LineState::InsertLine(int line) {
	if (lineStates.Length()) {
		lineStates.EnsureLength(line);
		lineStates.Insert(line, 0);
	}
}

void LineState::RemoveLine(int line) {
	if (lineStates.Length() > line) {
		lineStates.Delete(line);
	}
}

int LineState::SetLineState(int line, int state) {
	lineStates.EnsureLength(line + 1);
	int stateOld = lineStates[line];
	lineStates[line] = state;
	return stateOld;
}

int LineState::GetLineState(int line) {
	lineStates.EnsureLength(line + 1);
	return lineStates[line];
}

int LineState::GetMaxLineState() {
	return lineStates.Length();
}

static int NumberLines(const char *text) {
	if (text) {
		int newLines = 0;
		while (*text) {
			if (*text == '\n')
				newLines++;
			text++;
		}
		return newLines+1;
	} else {
		return 0;
	}
}

// Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
// and then has text and optional styles.

static const int IndividualStyles = 0x100;

struct AnnotationHeader {
	short style;	// Style IndividualStyles implies array of styles
	short lines;
	int length;
};

LineAnnotation::~LineAnnotation() {
	ClearAll();
}

void LineAnnotation::Init() {
	ClearAll();
}

void LineAnnotation::InsertLine(int line) {
	if (annotations.Length()) {
		annotations.Insert(line, 0);
	}
}

void LineAnnotation::RemoveLine(int line) {
	if (annotations.Length() && (line < annotations.Length())) {
		delete []annotations[line];
		annotations.Delete(line);
	}
}

bool LineAnnotation::AnySet() const {
	return annotations.Length() > 0;
}

bool LineAnnotation::MultipleStyles(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return reinterpret_cast<AnnotationHeader *>(annotations[line])->style == IndividualStyles;
	else
		return 0;
}

int LineAnnotation::Style(int line) {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return reinterpret_cast<AnnotationHeader *>(annotations[line])->style;
	else
		return 0;
}

const char *LineAnnotation::Text(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return annotations[line]+sizeof(AnnotationHeader);
	else
		return 0;
}

const unsigned char *LineAnnotation::Styles(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line] && MultipleStyles(line))
		return reinterpret_cast<unsigned char *>(annotations[line] + sizeof(AnnotationHeader) + Length(line));
	else
		return 0;
}

static char *AllocateAnnotation(int length, int style) {
	size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0);
	char *ret = new char[len];
	memset(ret, 0, len);
	return ret;
}

void LineAnnotation::SetText(int line, const char *text) {
	if (text) {
		annotations.EnsureLength(line+1);
		int style = Style(line);
		if (annotations[line]) {
			delete []annotations[line];
		}
		annotations[line] = AllocateAnnotation(strlen(text), style);
		AnnotationHeader *pah = reinterpret_cast<AnnotationHeader*>(annotations[line]);
		pah->style = static_cast<short>(style);
		pah->length = strlen(text);
		pah->lines = static_cast<short>(NumberLines(text));
		memcpy(annotations[line]+sizeof(AnnotationHeader), text, pah->length);
	} else {
		if (annotations.Length() && (line < annotations.Length()) && annotations[line]) {
			delete []annotations[line];
			annotations[line] = 0;
		}
	}
}

void LineAnnotation::ClearAll() {
	for (int line = 0; line < annotations.Length(); line++) {
		delete []annotations[line];
		annotations[line] = 0;
	}
	annotations.DeleteAll();
}

void LineAnnotation::SetStyle(int line, int style) {
	annotations.EnsureLength(line+1);
	if (!annotations[line]) {
		annotations[line] = AllocateAnnotation(0, style);
	}
	reinterpret_cast<AnnotationHeader *>(annotations[line])->style = static_cast<short>(style);
}

void LineAnnotation::SetStyles(int line, const unsigned char *styles) {
	annotations.EnsureLength(line+1);
	if (!annotations[line]) {
		annotations[line] = AllocateAnnotation(0, IndividualStyles);
	} else {
		AnnotationHeader *pahSource = reinterpret_cast<AnnotationHeader *>(annotations[line]);
		if (pahSource->style != IndividualStyles) {
			char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles);
			AnnotationHeader *pahAlloc = reinterpret_cast<AnnotationHeader *>(allocation);
			pahAlloc->length = pahSource->length;
			pahAlloc->lines = pahSource->lines;
			memcpy(allocation + sizeof(AnnotationHeader), annotations[line] + sizeof(AnnotationHeader), pahSource->length);
			delete []annotations[line];
			annotations[line] = allocation;
		}
	}
	AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
	pah->style = IndividualStyles;
	memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length);
}

int LineAnnotation::Length(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return reinterpret_cast<AnnotationHeader *>(annotations[line])->length;
	else
		return 0;
}

int LineAnnotation::Lines(int line) const {
	if (annotations.Length() && (line < annotations.Length()) && annotations[line])
		return reinterpret_cast<AnnotationHeader *>(annotations[line])->lines;
	else
		return 0;
}
<|endoftext|>


<commit_before>/*
 * Pyramid.cpp
 *
 *  Created on: Jun 26, 2013
 *      Author: goldman
 */

#include "Pyramid.h"

void Pyramid::climb(Random& rand, vector<bool> & solution, float & fitness, Evaluator& evaluator)
{
	add_unique(rand, solution, 0);
	for(size_t level=0; level < pops.size(); level++)
	{
		//use population clusters and population solutions to make new solution
		pops[level].improve(rand, solution, fitness, evaluator);
		add_unique(rand, solution, level);
	}
}

bool Pyramid::add_unique(Random& rand, const vector<bool> & solution, size_t level)
{
	if(seen.find(solution) == seen.end())
	{
		if(pops.size() == level)
		{
			pops.push_back(Population(length));
			pops[level].never_use_singletons();
		}
		pops[level].add(solution);
		pops[level].rebuild_tree(rand);
		seen.insert(solution);
		return true;
	}
	return false;
}

void Pyramid::optimize(Random& rand, Evaluator& evaluator, Configuration& config)
{
	float fitness = 0;
	auto hill_climber = config.get<hill_climb::pointer>("hill_climber");
	while(fitness < 1.0)
	{
		vector<bool> solution = rand_vector(rand, length);
		fitness = evaluator.evaluate(solution);
		hill_climber(rand, solution, fitness, evaluator);
		climb(rand, solution, fitness, evaluator);
	}
}
<commit_msg>Fixed bug preventing new levels from being created<commit_after>/*
 * Pyramid.cpp
 *
 *  Created on: Jun 26, 2013
 *      Author: goldman
 */

#include "Pyramid.h"

void Pyramid::climb(Random& rand, vector<bool> & solution, float & fitness, Evaluator& evaluator)
{
	add_unique(rand, solution, 0);
	for(size_t level=0; level < pops.size(); level++)
	{
		//use population clusters and population solutions to make new solution
		pops[level].improve(rand, solution, fitness, evaluator);
		add_unique(rand, solution, level+1);
	}
}

bool Pyramid::add_unique(Random& rand, const vector<bool> & solution, size_t level)
{
	if(seen.find(solution) == seen.end())
	{
		if(pops.size() == level)
		{
			pops.push_back(Population(length));
			pops[level].never_use_singletons();
		}
		pops[level].add(solution);
		pops[level].rebuild_tree(rand);
		seen.insert(solution);
		return true;
	}
	return false;
}

void Pyramid::optimize(Random& rand, Evaluator& evaluator, Configuration& config)
{
	float fitness = 0;
	auto hill_climber = config.get<hill_climb::pointer>("hill_climber");
	while(fitness < 1.0)
	{
		vector<bool> solution = rand_vector(rand, length);
		fitness = evaluator.evaluate(solution);
		hill_climber(rand, solution, fitness, evaluator);
		climb(rand, solution, fitness, evaluator);
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppUtils.h"
#include "QXmppIq.h"

#include <QDomElement>
#include <QXmlStreamWriter>

/// Constructs a QXmppIq with the specified \a type.
///
/// \param type

QXmppIq::QXmppIq(QXmppIq::Type type)
    : QXmppStanza(), m_type(type)
{
    generateAndSetNextId();
}

/// Returns the IQ's type.
///

QXmppIq::Type QXmppIq::type() const
{
    return m_type;
}

/// Sets the IQ's type.
///

void QXmppIq::setType(QXmppIq::Type type)
{
    m_type = type;
}

void QXmppIq::parse(const QDomElement &element)
{
    QXmppStanza::parse(element);
    setTypeFromStr(element.attribute("type"));
    parseElementFromChild(element);
}

void QXmppIq::parseElementFromChild(const QDomElement &element)
{
    QXmppElementList extensions;
    QDomElement itemElement = element.firstChildElement();
    while (!itemElement.isNull())
    {
        extensions.append(QXmppElement(itemElement));
        itemElement = itemElement.nextSiblingElement();
    }
    setExtensions(extensions);
}

void QXmppIq::toXml( QXmlStreamWriter *xmlWriter ) const
{
    xmlWriter->writeStartElement("iq");

    helperToXmlAddAttribute(xmlWriter, "id", id());
    helperToXmlAddAttribute(xmlWriter, "to", to());
    helperToXmlAddAttribute(xmlWriter, "from", from());
    if(getTypeStr().isEmpty())
        helperToXmlAddAttribute(xmlWriter, "type", "get");
    else
        helperToXmlAddAttribute(xmlWriter,  "type", getTypeStr());
    toXmlElementFromChild(xmlWriter);
    error().toXml(xmlWriter);
    xmlWriter->writeEndElement();
}

void QXmppIq::toXmlElementFromChild( QXmlStreamWriter *writer ) const
{
    foreach (const QXmppElement &extension, extensions())
        extension.toXml(writer);
}

QString QXmppIq::getTypeStr() const
{
    switch(m_type)
    {
    case QXmppIq::Error:
        return "error";
    case QXmppIq::Get:
        return "get";
    case QXmppIq::Set:
        return "set";
    case QXmppIq::Result:
        return "result";
    default:
        qWarning("QXmppIq::getTypeStr() invalid type %d", (int)m_type);
        return "";
    }
}

void QXmppIq::setTypeFromStr(const QString& str)
{
    if(str == "error")
    {
        setType(QXmppIq::Error);
        return;
    }
    else if(str == "get")
    {
        setType(QXmppIq::Get);
        return;
    }
    else if(str == "set")
    {
        setType(QXmppIq::Set);
        return;
    }
    else if(str == "result")
    {
        setType(QXmppIq::Result);
        return;
    }
    else
    {
        setType(static_cast<QXmppIq::Type>(-1));
        qWarning("QXmppIq::setTypeFromStr() invalid input string type: %s",
                 qPrintable(str));
        return;
    }
}

// deprecated

QXmppIq::Type QXmppIq::getType() const
{
    return m_type;
}

<commit_msg>silence a doxygen warning<commit_after>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppUtils.h"
#include "QXmppIq.h"

#include <QDomElement>
#include <QXmlStreamWriter>

/// Constructs a QXmppIq with the specified \a type.
///
/// \param type

QXmppIq::QXmppIq(QXmppIq::Type type)
    : QXmppStanza(), m_type(type)
{
    generateAndSetNextId();
}

/// Returns the IQ's type.
///

QXmppIq::Type QXmppIq::type() const
{
    return m_type;
}

/// Sets the IQ's type.
///
/// \param type

void QXmppIq::setType(QXmppIq::Type type)
{
    m_type = type;
}

void QXmppIq::parse(const QDomElement &element)
{
    QXmppStanza::parse(element);
    setTypeFromStr(element.attribute("type"));
    parseElementFromChild(element);
}

void QXmppIq::parseElementFromChild(const QDomElement &element)
{
    QXmppElementList extensions;
    QDomElement itemElement = element.firstChildElement();
    while (!itemElement.isNull())
    {
        extensions.append(QXmppElement(itemElement));
        itemElement = itemElement.nextSiblingElement();
    }
    setExtensions(extensions);
}

void QXmppIq::toXml( QXmlStreamWriter *xmlWriter ) const
{
    xmlWriter->writeStartElement("iq");

    helperToXmlAddAttribute(xmlWriter, "id", id());
    helperToXmlAddAttribute(xmlWriter, "to", to());
    helperToXmlAddAttribute(xmlWriter, "from", from());
    if(getTypeStr().isEmpty())
        helperToXmlAddAttribute(xmlWriter, "type", "get");
    else
        helperToXmlAddAttribute(xmlWriter,  "type", getTypeStr());
    toXmlElementFromChild(xmlWriter);
    error().toXml(xmlWriter);
    xmlWriter->writeEndElement();
}

void QXmppIq::toXmlElementFromChild( QXmlStreamWriter *writer ) const
{
    foreach (const QXmppElement &extension, extensions())
        extension.toXml(writer);
}

QString QXmppIq::getTypeStr() const
{
    switch(m_type)
    {
    case QXmppIq::Error:
        return "error";
    case QXmppIq::Get:
        return "get";
    case QXmppIq::Set:
        return "set";
    case QXmppIq::Result:
        return "result";
    default:
        qWarning("QXmppIq::getTypeStr() invalid type %d", (int)m_type);
        return "";
    }
}

void QXmppIq::setTypeFromStr(const QString& str)
{
    if(str == "error")
    {
        setType(QXmppIq::Error);
        return;
    }
    else if(str == "get")
    {
        setType(QXmppIq::Get);
        return;
    }
    else if(str == "set")
    {
        setType(QXmppIq::Set);
        return;
    }
    else if(str == "result")
    {
        setType(QXmppIq::Result);
        return;
    }
    else
    {
        setType(static_cast<QXmppIq::Type>(-1));
        qWarning("QXmppIq::setTypeFromStr() invalid input string type: %s",
                 qPrintable(str));
        return;
    }
}

// deprecated

QXmppIq::Type QXmppIq::getType() const
{
    return m_type;
}

<|endoftext|>


<commit_before>#include <cstring>
#include <utility>

#include "abort/abort.h"
#include "chess_util4.h"
#include "eval.h"
#include "MoveGen4.h"
#include "Search4.h"

namespace Chess
{
    Search4::Statistics::Statistics()
        : lnode_count(0),
          node_count(0),
          qnode_count(0)
    {
    }

    void Search4::Statistics::clear()
    {
        lnode_count = 0;
        node_count  = 0;
        qnode_count = 0;
    }

    Search4::Search4()
        : _aborted(false),
          _is_init(false),
          _max_depth(1),
          _next_node_check(0),
          _position(),
          _pv_set(),
          _start_time(),
          _stop_time()
    {
    }

    Search4::~Search4()
    {
    }

    std::vector<int32>
    Search4::get_pv(size_t index) const
    {
        AbortIfNot(index < _pv_set.size(), std::vector<int32>());

        return _pv_set[index];
    }

    auto Search4::get_stats() const -> Statistics
    {
        return _stats;
    }

    bool Search4::init(Handle<Position> pos)
    {
        _is_init = false;

        AbortIfNot(pos, false);

        _position = pos;

        _aborted = false;
        _next_node_check = 0;

        _stats.clear();

        const auto size = sizeof( _pv[0][0] )
            * max_ply * max_ply;

        std::memset(_pv, 0, size);

        _is_init = true;
        return true;
    }

    int16 Search4::quiesce(uint32 depth, int16 alpha, int16 beta)
    {
        Position& pos = *_position;

        const player_t to_move = pos.get_turn();
        const bool in_check    = pos.in_check(to_move);
        const auto& tables     = DataTables::get();

        BUFFER(int32, moves, max_moves);
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                /*
                 * Add a small penalty to the mate score to encourage
                 * mates closer to the root:
                 */
                return depth - king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);
        }

        /*
         * Get an initial score for this position:
         */
        const int16 score =
            tables.sign[ pos.get_turn() ] * evaluate(pos);

        if (alpha < score) alpha = score;

        /*
         * Return the heuristic value of this position if
         * no captures are left:
         */
        if (n_moves == 0 || max_ply <= depth)
        {
            _save_pv(depth, 0);

            _stats.lnode_count++;
            return score;
        }

        /*
         * Check if we can fail-high; not sure if this is
         * correct for zugzwang positions...
         */
        if (score >= beta)
        {
            _stats.lnode_count++;
            return beta;
        }

        int32 best_move = 0;

        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++; _stats.qnode_count++;

            const int32 move = moves[i];

            pos.make_move(move);

            const int16 score
                = -quiesce(depth + 1, -beta, -alpha );

            pos.unmake_move(move);

            if (score >= beta)
                return beta;

            if ( score > alpha )
            {
                best_move = move;
                alpha = score;
            }
        }

        _save_pv(depth, best_move);

        return alpha;
    }

    int16 Search4::run(uint32 depth, duration_t timeout)
    {
        AbortIfNot(_is_init , -king_value);
        AbortIfNot(depth > 0, -king_value);

        _start_time  =  std::chrono::steady_clock::now();
        _stop_time   =  _start_time + timeout;

        int16 score = -king_value;

        for (_max_depth =  1; _max_depth <= depth;
             _max_depth++)
        {
            _pv_set.clear();

            const int16 tmp_score = search_root();

            if ( _aborted ) break;
            score = tmp_score;

            // Display the principal variation
            // TODO Dump this to a stream configured
            // for UCI or human-readable format

            Position temp(*_position);
            const std::string line =
                MultiVariation::format( get_pv(0), temp);

            std::printf("[%2u]: %5hd --> %s\n",
                        _max_depth, score, line.c_str());
            std::fflush(stdout);
        }

        _is_init = false;
        return score;
    }

    int16 Search4::search(uint32 depth, int16 alpha, int16 beta)
    {
        if (_next_node_check <= _stats.node_count
            && _check_timeout())
        {
            _aborted = true; _stats.lnode_count++;
            return beta;
        }

        Position& pos = *_position;

        const player_t side = pos.get_turn();

        const bool in_check =
            pos.in_check( side );

        /*
         * Don't quiece() if we're in check:
         */
        if (_max_depth <= depth && !in_check)
            return quiesce( depth, alpha, beta );

        BUFFER(int32, moves, max_moves);
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                /*
                 * Add a small penalty to the mate score to encourage
                 * mates closer to the root:
                 */
                return depth - king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);

            n_moves += MoveGen::generate_noncaptures(
                pos, &moves[n_moves]);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                return 0;
            }
        }

        int32 best_move = 0;
        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++;

            const int32 move = moves[i];

            pos.make_move( move );

            const int16 score = -search(depth+1, -beta, -alpha);

            pos.unmake_move(move);

            if (beta <= score)
                return beta;

            if ( score > alpha )
            {
                best_move = move;
                alpha = score;
            }
        }

        if (best_move)
            _save_pv(depth, best_move);

        return alpha;
    }

    int16 Search4::search_root()
    {
        AbortIfNot( _position, false );

        Position& pos = *_position;

        const bool in_check =
            pos.in_check(pos.get_turn());

        BUFFER(int32, moves, max_moves );
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _save_pv(0, 0); return -king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);

            n_moves += MoveGen::generate_noncaptures(
                pos, &moves[n_moves]);
        }

        auto best = std::make_pair<int32,int16>(
            0, king_value+1);

        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++;

            const int32 move = moves[i];

            pos.make_move( move );

            const int16 score = search(1, -king_value,
                king_value);

            pos.unmake_move(move);

            if (score < best.second)
            {
                _save_pv(0, move);

                // Insert the newly computed variation

                _pv_set.insert(_get_pv(),
                    -best.second);

                best.first = move; best.second
                    = score;
            }
        }

        return -best.second;
    }

    bool Search4::setNumberOfLines(size_t size)
    {
        AbortIfNot(size < max_moves, false);
        _pv_set.reserve(size);

        return true;
    }

    bool Search4::_check_timeout()
    {
        const auto now = std::chrono::steady_clock::now();
        const auto dur = now - _start_time;

        if (_stop_time <= now)
            return true;

        // Check for timeouts once per second

        const auto nps =
            _stats.node_count * decltype(dur)::period::den /
                dur.count();

        _next_node_check =
            _stats.node_count + nps;

        return false;
    }

    MoveList Search4::_get_pv()
    {
        MoveList list; list.init(_pv[0], 0);

        for (size_t i = 0;
             _pv[0][i] && i < max_ply; i++ )
            list.size++;

        return list;
    }

    void Search4::_save_pv(uint32 depth, int32 move)
    {
        if (depth < max_ply)
        {
            _pv[depth][depth] = move;

            // Null move signals the end of a variation:
            if (move == 0) return;

            for  (uint32 i = depth + 1; i < max_ply; i += 1)
            {
                if ((_pv[depth][i] = _pv[depth+1][i])
                    == 0) break;
            }
        }
    }
}
<commit_msg>Fixed multi-PV output<commit_after>#include <cstring>
#include <utility>

#include "abort/abort.h"
#include "chess_util4.h"
#include "eval.h"
#include "MoveGen4.h"
#include "Search4.h"

namespace Chess
{
    Search4::Statistics::Statistics()
        : lnode_count(0),
          node_count(0),
          qnode_count(0)
    {
    }

    void Search4::Statistics::clear()
    {
        lnode_count = 0;
        node_count  = 0;
        qnode_count = 0;
    }

    Search4::Search4()
        : _aborted(false),
          _is_init(false),
          _max_depth(1),
          _next_node_check(0),
          _position(),
          _pv_set(),
          _start_time(),
          _stop_time()
    {
    }

    Search4::~Search4()
    {
    }

    std::vector<int32>
    Search4::get_pv(size_t index) const
    {
        AbortIfNot(index < _pv_set.size(), std::vector<int32>());

        return _pv_set[index];
    }

    auto Search4::get_stats() const -> Statistics
    {
        return _stats;
    }

    bool Search4::init(Handle<Position> pos)
    {
        _is_init = false;

        AbortIfNot(pos, false);

        _position = pos;

        _aborted = false;
        _next_node_check = 0;

        _stats.clear();

        const auto size = sizeof( _pv[0][0] )
            * max_ply * max_ply;

        std::memset(_pv, 0, size);

        _is_init = true;
        return true;
    }

    int16 Search4::quiesce(uint32 depth, int16 alpha, int16 beta)
    {
        Position& pos = *_position;

        const player_t to_move = pos.get_turn();
        const bool in_check    = pos.in_check(to_move);
        const auto& tables     = DataTables::get();

        BUFFER(int32, moves, max_moves);
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                /*
                 * Add a small penalty to the mate score to encourage
                 * mates closer to the root:
                 */
                return depth - king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);
        }

        /*
         * Get an initial score for this position:
         */
        const int16 score =
            tables.sign[ pos.get_turn() ] * evaluate(pos);

        if (alpha < score) alpha = score;

        /*
         * Return the heuristic value of this position if
         * no captures are left:
         */
        if (n_moves == 0 || max_ply <= depth)
        {
            _save_pv(depth, 0);

            _stats.lnode_count++;
            return score;
        }

        /*
         * Check if we can fail-high; not sure if this is
         * correct for zugzwang positions...
         */
        if (score >= beta)
        {
            _stats.lnode_count++;
            return beta;
        }

        int32 best_move = 0;

        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++; _stats.qnode_count++;

            const int32 move = moves[i];

            pos.make_move(move);

            const int16 score
                = -quiesce(depth + 1, -beta, -alpha );

            pos.unmake_move(move);

            if (score >= beta)
                return beta;

            if ( score > alpha )
            {
                best_move = move;
                alpha = score;
            }
        }

        _save_pv(depth, best_move);

        return alpha;
    }

    int16 Search4::run(uint32 depth, duration_t timeout)
    {
        AbortIfNot(_is_init , -king_value);
        AbortIfNot(depth > 0, -king_value);

        _start_time  =  std::chrono::steady_clock::now();
        _stop_time   =  _start_time + timeout;

        int16 score = -king_value;

        for (_max_depth =  1; _max_depth <= depth;
             _max_depth++)
        {
            _pv_set.clear();

            const int16 tmp_score = search_root();

            if ( _aborted ) break;
            score = tmp_score;

            // Display the principal variation
            // TODO Dump this to a stream configured
            // for UCI or human-readable format

            for (size_t i = 0; i < _pv_set.size(); i++)
            {
                int16 pvs;
                const std::vector<int32> line_v = _pv_set.get(i, pvs);

                Position temp(*_position);
                const std::string line =
                    MultiVariation::format(line_v, temp);

                std::printf("[%2u]: %5hd --> %s \n" , _max_depth, pvs,
                            line.c_str());
                std::fflush(stdout);
            }
        }

        _is_init = false;
        return score;
    }

    int16 Search4::search(uint32 depth, int16 alpha, int16 beta)
    {
        if (_next_node_check <= _stats.node_count
            && _check_timeout())
        {
            _aborted = true; _stats.lnode_count++;
            return beta;
        }

        Position& pos = *_position;

        const player_t side = pos.get_turn();

        const bool in_check =
            pos.in_check( side );

        /*
         * Don't quiece() if we're in check:
         */
        if (_max_depth <= depth && !in_check)
            return quiesce( depth, alpha, beta );

        BUFFER(int32, moves, max_moves);
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                /*
                 * Add a small penalty to the mate score to encourage
                 * mates closer to the root:
                 */
                return depth - king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);

            n_moves += MoveGen::generate_noncaptures(
                pos, &moves[n_moves]);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                return 0;
            }
        }

        int32 best_move = 0;
        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++;

            const int32 move = moves[i];

            pos.make_move( move );

            const int16 score = -search(depth+1, -beta, -alpha);

            pos.unmake_move(move);

            if (beta <= score)
                return beta;

            if ( score > alpha )
            {
                best_move = move;
                alpha = score;
            }
        }

        if (best_move)
            _save_pv(depth, best_move);

        return alpha;
    }

    int16 Search4::search_root()
    {
        AbortIfNot( _position, false );

        Position& pos = *_position;

        const bool in_check =
            pos.in_check(pos.get_turn());

        BUFFER(int32, moves, max_moves );
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _save_pv(0, 0); return -king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);

            n_moves += MoveGen::generate_noncaptures(
                pos, &moves[n_moves]);
        }

        auto best = std::make_pair<int32,int16>(
            0, king_value+1);

        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++;

            const int32 move = moves[i];

            pos.make_move( move );

            const int16 score = search(1, -king_value,
                king_value);

            pos.unmake_move(move);

            _save_pv(0, move);

            if (score < best.second)
            {
                best.first = move; best.second
                    = score;
            }

            // Insert the newly computed variation

            _pv_set.insert(_get_pv(),
                -score);
        }

        return -best.second;
    }

    bool Search4::setNumberOfLines(size_t size)
    {
        AbortIfNot(size < max_moves, false);
        _pv_set.reserve(size);

        return true;
    }

    bool Search4::_check_timeout()
    {
        const auto now = std::chrono::steady_clock::now();
        const auto dur = now - _start_time;

        if (_stop_time <= now)
            return true;

        // Check for timeouts once per second

        const auto nps =
            _stats.node_count * decltype(dur)::period::den /
                dur.count();

        _next_node_check =
            _stats.node_count + nps;

        return false;
    }

    MoveList Search4::_get_pv()
    {
        MoveList list; list.init(_pv[0], 0);

        for (size_t i = 0;
             _pv[0][i] && i < max_ply; i++ )
            list.size++;

        return list;
    }

    void Search4::_save_pv(uint32 depth, int32 move)
    {
        if (depth < max_ply)
        {
            _pv[depth][depth] = move;

            // Null move signals the end of a variation:
            if (move == 0) return;

            for  (uint32 i = depth + 1; i < max_ply; i += 1)
            {
                if ((_pv[depth][i] = _pv[depth+1][i])
                    == 0) break;
            }
        }
    }
}
<|endoftext|>


<commit_before>#include "TestApp.h"
#include <Platform\Window.h>
#include <LibRetroServer\CoreProcess.h>
#include <thread>
#include <vector>
#include <core\algorithm.h>

using namespace std::chrono_literals;

class TestApp : public ITestApp
{
public:
	TestApp();
	virtual ~TestApp();
	void Run() override;
private:
	std::unique_ptr<CR::Platform::IWindow> m_window;
	std::vector<std::unique_ptr<CR::LibRetroServer::ICoreProcess>> m_cores;
};

TestApp::TestApp()
{
	m_window = CR::Platform::CRCreateWindow("Lib Retro Server", 500, 500);

	m_cores.push_back(CR::LibRetroServer::CreateCoreProcess());
	m_cores.push_back(CR::LibRetroServer::CreateCoreProcess());
	m_cores.push_back(CR::LibRetroServer::CreateCoreProcess());
	m_cores.push_back(CR::LibRetroServer::CreateCoreProcess());
}

TestApp::~TestApp()
{
	CR::Core::ForEach(m_cores, [](auto& core) {	core->WaitForClose(10s); });
}

void TestApp::Run()
{
	std::this_thread::sleep_for(2s);
}

std::unique_ptr<ITestApp> CreateTestApp()
{
	return std::make_unique<TestApp>();
}<commit_msg>bug fixes<commit_after>#include "TestApp.h"
#include <Platform\Window.h>
#include <LibRetroServer\CoreProcess.h>
#include <thread>
#include <vector>
#include <core\algorithm.h>

using namespace std::chrono_literals;

class TestApp : public ITestApp
{
public:
	TestApp();
	virtual ~TestApp();
	void Run() override;
private:
	void OnDestroy();
	volatile bool m_finished{false};

	std::unique_ptr<CR::Platform::IWindow> m_window;
	std::vector<std::unique_ptr<CR::LibRetroServer::ICoreProcess>> m_cores;
};

TestApp::TestApp()
{
	m_window = CR::Platform::CRCreateWindow("Lib Retro Server", 500, 500, [this]() { this->OnDestroy(); });

	m_cores.push_back(CR::LibRetroServer::CreateCoreProcess());
	//m_cores.push_back(CR::LibRetroServer::CreateCoreProcess());
	//m_cores.push_back(CR::LibRetroServer::CreateCoreProcess());
	//m_cores.push_back(CR::LibRetroServer::CreateCoreProcess());

	m_cores[0]->Initialize("mame_libretro.dll", "galaga.zip");
	//m_cores[1]->Initialize("mame_libretro.dll", "joust.zip");
	//m_cores[2]->Initialize("mame_libretro.dll", "pacplus.zip");
	//m_cores[3]->Initialize("mame_libretro.dll", "goldnaxe.zip");
}

TestApp::~TestApp()
{
	CR::Core::ForEach(m_cores, [](auto& core) {	core->WaitForClose(10s); });
}

void TestApp::Run()
{
	while(!m_finished)
	{
		std::this_thread::sleep_for(1s);
	}
}

void TestApp::OnDestroy()
{
	m_finished = true;
	CR::Core::ForEach(m_cores, [](auto& core) {	core->Shutdown(); });
}

std::unique_ptr<ITestApp> CreateTestApp()
{
	return std::make_unique<TestApp>();
}<|endoftext|>


<commit_before>/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "frontends/lean/pp.h"
#include "api/string.h"
#include "api/exception.h"
#include "api/decl.h"
#include "api/lean_env.h"
#include "api/ios.h"
using namespace lean; // NOLINT

lean_bool lean_ios_mk_std(lean_options o, lean_ios * r, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(o);
    io_state ios(mk_pretty_formatter_factory(), to_options_ref(o));
    *r = of_io_state(new io_state(ios));
    LEAN_CATCH;
}

lean_bool lean_ios_mk_buffered(lean_options o, lean_ios * r, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(o);
    io_state ios(mk_pretty_formatter_factory(), to_options_ref(o));
    ios.set_regular_channel(std::make_shared<string_output_channel>());
    ios.set_diagnostic_channel(std::make_shared<string_output_channel>());
    *r = of_io_state(new io_state(ios));
    LEAN_CATCH;
}

void lean_ios_del(lean_ios ios) {
    delete to_io_state(ios);
}

lean_bool lean_ios_is_std(lean_ios ios) {
    if (!ios)
        return lean_false;
    return dynamic_cast<string_output_channel*>(&to_io_state_ref(ios).get_regular_channel()) != nullptr;
}

lean_bool lean_ios_set_options(lean_ios ios, lean_options o, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(ios);
    check_nonnull(o);
    to_io_state(ios)->set_options(to_options_ref(o));
    LEAN_CATCH;
}

lean_bool lean_ios_get_options(lean_ios ios, lean_options * r, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(ios);
    *r = of_options(new options(to_io_state_ref(ios).get_options()));
    LEAN_CATCH;
}

static void check_nonstd(lean_ios ios) {
    check_nonnull(ios);
    if (lean_ios_is_std(ios))
        throw exception("invalid argument, buffered IO state expected");
}

lean_bool lean_ios_get_regular(lean_ios ios, char const ** r, lean_exception * ex) {
    LEAN_TRY;
    check_nonstd(ios);
    *r = mk_string(static_cast<string_output_channel&>(to_io_state_ref(ios).get_regular_channel()).str());
    LEAN_CATCH;
}

lean_bool lean_ios_get_diagnostic(lean_ios ios, char const ** r, lean_exception * ex) {
    LEAN_TRY;
    check_nonstd(ios);
    *r = mk_string(static_cast<string_output_channel&>(to_io_state_ref(ios).get_diagnostic_channel()).str());
    LEAN_CATCH;
}

lean_bool lean_ios_reset_regular(lean_ios ios, lean_exception * ex) {
    LEAN_TRY;
    check_nonstd(ios);
    to_io_state(ios)->set_regular_channel(std::make_shared<string_output_channel>());
    LEAN_CATCH;
}

lean_bool lean_ios_reset_diagnostic(lean_ios ios, lean_exception * ex) {
    LEAN_TRY;
    check_nonstd(ios);
    to_io_state(ios)->set_diagnostic_channel(std::make_shared<string_output_channel>());
    LEAN_CATCH;
}

lean_bool lean_expr_to_pp_string(lean_env env, lean_ios ios, lean_expr e, char const ** r, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(env);
    check_nonnull(ios);
    check_nonnull(e);
    options const & o = to_io_state_ref(ios).get_options();
    formatter fmt = to_io_state_ref(ios).get_formatter_factory()(to_env_ref(env), o);
    std::ostringstream out;
    out << mk_pair(fmt(to_expr_ref(e)), o);
    *r = mk_string(out.str());
    LEAN_CATCH;
}
<commit_msg>fix(api): lean_ios_is_std returned incorrect result<commit_after>/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "frontends/lean/pp.h"
#include "api/string.h"
#include "api/exception.h"
#include "api/decl.h"
#include "api/lean_env.h"
#include "api/ios.h"
using namespace lean; // NOLINT

lean_bool lean_ios_mk_std(lean_options o, lean_ios * r, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(o);
    io_state ios(mk_pretty_formatter_factory(), to_options_ref(o));
    *r = of_io_state(new io_state(ios));
    LEAN_CATCH;
}

lean_bool lean_ios_mk_buffered(lean_options o, lean_ios * r, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(o);
    io_state ios(mk_pretty_formatter_factory(), to_options_ref(o));
    ios.set_regular_channel(std::make_shared<string_output_channel>());
    ios.set_diagnostic_channel(std::make_shared<string_output_channel>());
    *r = of_io_state(new io_state(ios));
    LEAN_CATCH;
}

void lean_ios_del(lean_ios ios) {
    delete to_io_state(ios);
}

lean_bool lean_ios_is_std(lean_ios ios) {
    if (!ios)
        return lean_false;
    return dynamic_cast<string_output_channel*>(&to_io_state_ref(ios).get_regular_channel()) == nullptr;
}

lean_bool lean_ios_set_options(lean_ios ios, lean_options o, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(ios);
    check_nonnull(o);
    to_io_state(ios)->set_options(to_options_ref(o));
    LEAN_CATCH;
}

lean_bool lean_ios_get_options(lean_ios ios, lean_options * r, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(ios);
    *r = of_options(new options(to_io_state_ref(ios).get_options()));
    LEAN_CATCH;
}

static void check_nonstd(lean_ios ios) {
    check_nonnull(ios);
    if (lean_ios_is_std(ios))
        throw exception("invalid argument, buffered IO state expected");
}

lean_bool lean_ios_get_regular(lean_ios ios, char const ** r, lean_exception * ex) {
    LEAN_TRY;
    check_nonstd(ios);
    *r = mk_string(static_cast<string_output_channel&>(to_io_state_ref(ios).get_regular_channel()).str());
    LEAN_CATCH;
}

lean_bool lean_ios_get_diagnostic(lean_ios ios, char const ** r, lean_exception * ex) {
    LEAN_TRY;
    check_nonstd(ios);
    *r = mk_string(static_cast<string_output_channel&>(to_io_state_ref(ios).get_diagnostic_channel()).str());
    LEAN_CATCH;
}

lean_bool lean_ios_reset_regular(lean_ios ios, lean_exception * ex) {
    LEAN_TRY;
    check_nonstd(ios);
    to_io_state(ios)->set_regular_channel(std::make_shared<string_output_channel>());
    LEAN_CATCH;
}

lean_bool lean_ios_reset_diagnostic(lean_ios ios, lean_exception * ex) {
    LEAN_TRY;
    check_nonstd(ios);
    to_io_state(ios)->set_diagnostic_channel(std::make_shared<string_output_channel>());
    LEAN_CATCH;
}

lean_bool lean_expr_to_pp_string(lean_env env, lean_ios ios, lean_expr e, char const ** r, lean_exception * ex) {
    LEAN_TRY;
    check_nonnull(env);
    check_nonnull(ios);
    check_nonnull(e);
    options const & o = to_io_state_ref(ios).get_options();
    formatter fmt = to_io_state_ref(ios).get_formatter_factory()(to_env_ref(env), o);
    std::ostringstream out;
    out << mk_pair(fmt(to_expr_ref(e)), o);
    *r = mk_string(out.str());
    LEAN_CATCH;
}
<|endoftext|>


<commit_before>#include "include/toml.h"

#include <cstdlib>
#include <vector>
#include <map>

using namespace ctoml;

TomlDocument::const_iterator TomlDocument::cbegin() const {
   return values_.cbegin();
}

TomlDocument::const_iterator TomlDocument::cend() const {
   return values_.cend();
}

void TomlDocument::insert(std::string key, std::shared_ptr<TomlValue> value) {
   values_.emplace(key, value);
}

void TomlDocument::insert(std::string key, std::unique_ptr<TomlValue> value) {
   insert(key, std::shared_ptr<TomlValue>(move(value)));
}

void TomlDocument::set(std::string key, std::shared_ptr<TomlValue> value) {
   values_[key] = value;
}

void TomlDocument::set(std::string key, std::unique_ptr<TomlValue> value) {
   set(key, std::shared_ptr<TomlValue>(move(value)));
}

bool TomlDocument::is_key(std::string key) const {
   return values_.find(key) != values_.end();
}

std::shared_ptr<TomlValue> TomlDocument::get(std::string key) const {
   return is_key(key) ? values_.find(key)->second : nullptr;
}

std::ostream &TomlDocument::write(std::ostream &out) {
   // Sort key groups by key in lexographical order (but putting those with root key in front)
   std::map<std::string, std::shared_ptr<TomlValue>> map;

   // Add each key to the map to sort it
   for (auto it = cbegin(); it != cend(); ++it) {
      if (it->first.find(".") == std::string::npos) {
         map.insert(std::make_pair("." + it->first, it->second));
      } else {
         map.insert(std::make_pair(it->first, it->second));
      }
   }

   // Write each key group
   std::string prevPrefix, prefix, suffix;
   for (auto it = map.cbegin(); it != map.cend(); ++it) {
      // Get the value of this key (TODO: escape the value e.g. convert '\n' to '\\n')
      std::string value = it->second->to_string();

      // Get the key without the last '.'
      auto pos = it->first.rfind(".");
      if (pos != std::string::npos) {
         prefix = it->first.substr(0, pos);
         suffix = it->first.substr(pos + 1);

         // If this is a different key group
         if (prevPrefix != prefix) {
            // Write the key prefix
            out << "[" << prefix << "]" << std::endl;
         }
      } else {
         prefix = "";
         suffix = it->first;
      }

      // Write out the contents of this key
      out << suffix << " = " << value << std::endl;
      prevPrefix = prefix;
   }

   return out;
}

TomlParser::TomlParser() {

}

TomlParser::TomlParser(std::string filename) {
   open(filename);
}

void TomlParser::error(const char *format, ...) {
   char buffer[1024];

   va_list args; va_start(args, format);
   vsnprintf(buffer, 1024, format, args);
   va_end(args);

   errors_.push_back(TomlError(buffer, cur_line));

   // Now we skip to the next line
   while (next_char() != '\n' && cur()) { }
   next_char();
}

bool TomlParser::is_whitespace(char c, bool new_line) {
   return c == '\t' || c == ' ' || (c == '\n' && new_line);
}

bool TomlParser::is_numeric(char c, bool dot) {
   return (c == dot && dot) || (c >= '0' && c <= '9');
}

bool TomlParser::is_integer(std::string str) {
   // An integer must have only numeric digits. It may start with with a '-'.
   if (str == "") return false;
   if (!is_numeric(str[0]) && str[0] != '-') return false;

   for (auto ch : str.substr(1)) {
      if (!is_numeric(ch)) return false;
   }

   return true;
}

bool TomlParser::is_float(std::string str) {
   // A decimal may have a decimal point and a sign.
   if (str == "") return false;
   if (!is_numeric(str[0]) && str[0] != '-') return false;

   bool decimal = false;
   for (auto ch : str.substr(1)) {
      if (ch == '.') {
         if (decimal) return false; // Double decimal point
         decimal = true;
      } else if(!is_numeric(ch)) return false;
   }

   return true;
}

bool TomlParser::is_datetime(std::string str) {
   // A datetime has the format YYYY-MM-DDThh:mm:ssZ
   // GCC still has an incomplete support for regex,
   // so it is not used here
   if (str.length() != 20) return false;
   return str[4] == '-' && str[7] == '-' && str[10] == 'T' &&
      str[13] == ':' && str[16] == ':' && str[19] == 'Z';
}

tm TomlParser::to_time(std::string str) {
   int year, mon, mday, hour, min, sec;
   sscanf(str.c_str(), "%d-%d-%dT%d:%d:%dZ", &year, &mon, &mday, &hour, &min, &sec);

   tm date;
   date.tm_year = year - 1900;
   date.tm_mon = mon - 1;
   date.tm_mday = mday;
   date.tm_hour = hour + 1;
   date.tm_min = min;
   date.tm_sec = sec;

   return date;
}

char TomlParser::next_char() {
   char ch = source_file_.get();
   *cur_ = (ch == EOF ? '\0' : ch);

   if (cur() == '\n') cur_line++;
   return cur();
}

char TomlParser::next_skip_whitespace(bool new_lines) {
   while(next_char() && is_whitespace(cur(), new_lines)) { }
   return cur();
}

void TomlParser::expect(char c) {
   if (cur() != c) error("Expected '%c'", c);
   next_char();
}

void TomlParser::advance(char c, bool new_line) {
   skip_whitespace(new_line);
   expect(c);
}

void TomlParser::skip_whitespace(bool new_line) {
   if (is_whitespace(cur(), new_line)) next_skip_whitespace(new_line);
}

void TomlParser::skip_whitespace_and_comments() {
   while (cur() && (is_whitespace(cur(), true) || cur() == '#')) {
      if (cur() == '#') {
         while (cur() && cur() != '\n') next_char();
      }
      next_char();
   }
}

std::shared_ptr<TomlValue> TomlParser::parse_string() {
   // A string is a double quoted string literal
   std::string str;

   expect('"');
   while (cur()) {
      char c = cur(); next_char();

      // Handle special characters
      if (c == '\\' && cur()) {
         // TODO(evilncrazy): support null characters
         if (cur() == 't') c = '\t';
         else if (cur() == 'n') c = '\n';
         else if (cur() == 'r') c = '\r';
         else if (cur() == '"') c = '"';
         else if (cur() == '\\') c = '\\';
         else {
            error("Invalid escape character \\%c", cur());
            return nullptr;
         }

         next_char();
      } else if (c == '"') {
         // String closed in a double quote
         break;
      }

      str += c;
   }

   return TomlValue::create_string(str);
}

std::shared_ptr<TomlValue> TomlParser::parse_number() {
   std::string number;
   while (cur() && !is_whitespace(cur(), true) && cur() != ',' && cur() != ']') {
      number += cur();
      next_char();
   }

   // Decide what data type it is
   if (is_integer(number)) return TomlValue::create_int(atoll(number.c_str()));
   if (is_float(number)) return TomlValue::create_float(atof(number.c_str()));
   if (is_datetime(number)) return TomlValue::create_datetime(to_time(number));

   error("\"%s\" is not a valid value", number.c_str());
   return nullptr;
}

std::shared_ptr<TomlValue> TomlParser::parse_boolean() {
   std::string str;
   while (cur() && !is_whitespace(cur(), true)) {
      str += cur();
      next_char();
   }

   if (str == "true") return TomlValue::create_boolean(true);
   else if(str == "false") return TomlValue::create_boolean(false);
   else {
      error("\"%s\" is not a valid value", str.c_str());
      return nullptr;
   }
}

std::shared_ptr<TomlValue> TomlParser::parse_array() {
   expect('[');

   auto array = std::static_pointer_cast<TomlArray>(std::shared_ptr<TomlValue>(TomlValue::create_array()));
   while (cur() && cur() != ']') {
      skip_whitespace_and_comments();
      array->add(parse_value());

      skip_whitespace_and_comments();
      if (cur() == ']') break;
      advance(',');
      skip_whitespace_and_comments(); // Need this for trailing commas
   }

   advance(']');
   return array;
}

std::string TomlParser::parse_key_group() {
   expect('[');

   // Read until close bracket
   std::string key;
   while (cur() && cur() != ']') {
      key += cur();
      next_char();
   }

   expect(']');
   return key;
}

std::shared_ptr<TomlValue> TomlParser::parse_value() {
   if (cur() == '"') return parse_string();
   if (is_numeric(cur()) || cur() == '-') return parse_number();
   if (cur() == '[') return parse_array();
   return parse_boolean();
}

std::string TomlParser::parse_key() {
   std::string key;
   while (cur() && !is_whitespace(cur()) && cur() != '=') {
      key += cur();
      next_char();
   }

   return key;
}

TomlDocument TomlParser::parse() {
   if (!good()) {
      // Return empty document error in file
      return TomlDocument();
   }

   // The final document
   TomlDocument doc;

   std::string cur_group;

   // Find next non-whitespace character
   while (skip_whitespace_and_comments(), cur()) {
      if(cur() == '[') {
         // Key group (it's not an array as an array is always a value)
         cur_group = parse_key_group() + ".";
      } else {
         std::string key = cur_group + parse_key();
         advance('='); skip_whitespace();

         std::shared_ptr<TomlValue> value = parse_value();
         if (value) {
            // We check all the prefix key groups to ensure that they haven't
            // already been defined previously
            size_t dot_pos = 0;
            while (dot_pos = key.find(".", dot_pos + 1), dot_pos != std::string::npos) {
               std::string key_group(key, 0, dot_pos);
               if(doc.is_key(key_group)) {
                  error("The key '%s' has already been used", key_group.c_str());
                  break;
               }
            }

            // Now check the whole key
            if (!doc.is_key(key)) {
               if (success())
                  doc.insert(key, value);
            } else {
               error("The key '%s' has already been used", key.c_str());
            }
         }
      }
   }

   return doc;
}

bool TomlParser::good() const {
   return source_file_.good();
}

bool TomlParser::success() const {
   return errors_.size() == 0;
}

bool TomlParser::open(const std::string filename) {
   source_file_.open(filename);
   cur_ = new char(' '); // Dummy value

   return source_file_.good();
}

void TomlParser::close() {
    source_file_.close();
}
<commit_msg>After TomlParser::parse() is done, before returning the doc object, close the file.<commit_after>#include "include/toml.h"

#include <cstdlib>
#include <vector>
#include <map>

using namespace ctoml;

TomlDocument::const_iterator TomlDocument::cbegin() const {
   return values_.cbegin();
}

TomlDocument::const_iterator TomlDocument::cend() const {
   return values_.cend();
}

void TomlDocument::insert(std::string key, std::shared_ptr<TomlValue> value) {
   values_.emplace(key, value);
}

void TomlDocument::insert(std::string key, std::unique_ptr<TomlValue> value) {
   insert(key, std::shared_ptr<TomlValue>(move(value)));
}

void TomlDocument::set(std::string key, std::shared_ptr<TomlValue> value) {
   values_[key] = value;
}

void TomlDocument::set(std::string key, std::unique_ptr<TomlValue> value) {
   set(key, std::shared_ptr<TomlValue>(move(value)));
}

bool TomlDocument::is_key(std::string key) const {
   return values_.find(key) != values_.end();
}

std::shared_ptr<TomlValue> TomlDocument::get(std::string key) const {
   return is_key(key) ? values_.find(key)->second : nullptr;
}

std::ostream &TomlDocument::write(std::ostream &out) {
   // Sort key groups by key in lexographical order (but putting those with root key in front)
   std::map<std::string, std::shared_ptr<TomlValue>> map;

   // Add each key to the map to sort it
   for (auto it = cbegin(); it != cend(); ++it) {
      if (it->first.find(".") == std::string::npos) {
         map.insert(std::make_pair("." + it->first, it->second));
      } else {
         map.insert(std::make_pair(it->first, it->second));
      }
   }

   // Write each key group
   std::string prevPrefix, prefix, suffix;
   for (auto it = map.cbegin(); it != map.cend(); ++it) {
      // Get the value of this key (TODO: escape the value e.g. convert '\n' to '\\n')
      std::string value = it->second->to_string();

      // Get the key without the last '.'
      auto pos = it->first.rfind(".");
      if (pos != std::string::npos) {
         prefix = it->first.substr(0, pos);
         suffix = it->first.substr(pos + 1);

         // If this is a different key group
         if (prevPrefix != prefix) {
            // Write the key prefix
            out << "[" << prefix << "]" << std::endl;
         }
      } else {
         prefix = "";
         suffix = it->first;
      }

      // Write out the contents of this key
      out << suffix << " = " << value << std::endl;
      prevPrefix = prefix;
   }

   return out;
}

TomlParser::TomlParser() {

}

TomlParser::TomlParser(std::string filename) {
   open(filename);
}

void TomlParser::error(const char *format, ...) {
   char buffer[1024];

   va_list args; va_start(args, format);
   vsnprintf(buffer, 1024, format, args);
   va_end(args);

   errors_.push_back(TomlError(buffer, cur_line));

   // Now we skip to the next line
   while (next_char() != '\n' && cur()) { }
   next_char();
}

bool TomlParser::is_whitespace(char c, bool new_line) {
   return c == '\t' || c == ' ' || (c == '\n' && new_line);
}

bool TomlParser::is_numeric(char c, bool dot) {
   return (c == dot && dot) || (c >= '0' && c <= '9');
}

bool TomlParser::is_integer(std::string str) {
   // An integer must have only numeric digits. It may start with with a '-'.
   if (str == "") return false;
   if (!is_numeric(str[0]) && str[0] != '-') return false;

   for (auto ch : str.substr(1)) {
      if (!is_numeric(ch)) return false;
   }

   return true;
}

bool TomlParser::is_float(std::string str) {
   // A decimal may have a decimal point and a sign.
   if (str == "") return false;
   if (!is_numeric(str[0]) && str[0] != '-') return false;

   bool decimal = false;
   for (auto ch : str.substr(1)) {
      if (ch == '.') {
         if (decimal) return false; // Double decimal point
         decimal = true;
      } else if(!is_numeric(ch)) return false;
   }

   return true;
}

bool TomlParser::is_datetime(std::string str) {
   // A datetime has the format YYYY-MM-DDThh:mm:ssZ
   // GCC still has an incomplete support for regex,
   // so it is not used here
   if (str.length() != 20) return false;
   return str[4] == '-' && str[7] == '-' && str[10] == 'T' &&
      str[13] == ':' && str[16] == ':' && str[19] == 'Z';
}

tm TomlParser::to_time(std::string str) {
   int year, mon, mday, hour, min, sec;
   sscanf(str.c_str(), "%d-%d-%dT%d:%d:%dZ", &year, &mon, &mday, &hour, &min, &sec);

   tm date;
   date.tm_year = year - 1900;
   date.tm_mon = mon - 1;
   date.tm_mday = mday;
   date.tm_hour = hour + 1;
   date.tm_min = min;
   date.tm_sec = sec;

   return date;
}

char TomlParser::next_char() {
   char ch = source_file_.get();
   *cur_ = (ch == EOF ? '\0' : ch);

   if (cur() == '\n') cur_line++;
   return cur();
}

char TomlParser::next_skip_whitespace(bool new_lines) {
   while(next_char() && is_whitespace(cur(), new_lines)) { }
   return cur();
}

void TomlParser::expect(char c) {
   if (cur() != c) error("Expected '%c'", c);
   next_char();
}

void TomlParser::advance(char c, bool new_line) {
   skip_whitespace(new_line);
   expect(c);
}

void TomlParser::skip_whitespace(bool new_line) {
   if (is_whitespace(cur(), new_line)) next_skip_whitespace(new_line);
}

void TomlParser::skip_whitespace_and_comments() {
   while (cur() && (is_whitespace(cur(), true) || cur() == '#')) {
      if (cur() == '#') {
         while (cur() && cur() != '\n') next_char();
      }
      next_char();
   }
}

std::shared_ptr<TomlValue> TomlParser::parse_string() {
   // A string is a double quoted string literal
   std::string str;

   expect('"');
   while (cur()) {
      char c = cur(); next_char();

      // Handle special characters
      if (c == '\\' && cur()) {
         // TODO(evilncrazy): support null characters
         if (cur() == 't') c = '\t';
         else if (cur() == 'n') c = '\n';
         else if (cur() == 'r') c = '\r';
         else if (cur() == '"') c = '"';
         else if (cur() == '\\') c = '\\';
         else {
            error("Invalid escape character \\%c", cur());
            return nullptr;
         }

         next_char();
      } else if (c == '"') {
         // String closed in a double quote
         break;
      }

      str += c;
   }

   return TomlValue::create_string(str);
}

std::shared_ptr<TomlValue> TomlParser::parse_number() {
   std::string number;
   while (cur() && !is_whitespace(cur(), true) && cur() != ',' && cur() != ']') {
      number += cur();
      next_char();
   }

   // Decide what data type it is
   if (is_integer(number)) return TomlValue::create_int(atoll(number.c_str()));
   if (is_float(number)) return TomlValue::create_float(atof(number.c_str()));
   if (is_datetime(number)) return TomlValue::create_datetime(to_time(number));

   error("\"%s\" is not a valid value", number.c_str());
   return nullptr;
}

std::shared_ptr<TomlValue> TomlParser::parse_boolean() {
   std::string str;
   while (cur() && !is_whitespace(cur(), true)) {
      str += cur();
      next_char();
   }

   if (str == "true") return TomlValue::create_boolean(true);
   else if(str == "false") return TomlValue::create_boolean(false);
   else {
      error("\"%s\" is not a valid value", str.c_str());
      return nullptr;
   }
}

std::shared_ptr<TomlValue> TomlParser::parse_array() {
   expect('[');

   auto array = std::static_pointer_cast<TomlArray>(std::shared_ptr<TomlValue>(TomlValue::create_array()));
   while (cur() && cur() != ']') {
      skip_whitespace_and_comments();
      array->add(parse_value());

      skip_whitespace_and_comments();
      if (cur() == ']') break;
      advance(',');
      skip_whitespace_and_comments(); // Need this for trailing commas
   }

   advance(']');
   return array;
}

std::string TomlParser::parse_key_group() {
   expect('[');

   // Read until close bracket
   std::string key;
   while (cur() && cur() != ']') {
      key += cur();
      next_char();
   }

   expect(']');
   return key;
}

std::shared_ptr<TomlValue> TomlParser::parse_value() {
   if (cur() == '"') return parse_string();
   if (is_numeric(cur()) || cur() == '-') return parse_number();
   if (cur() == '[') return parse_array();
   return parse_boolean();
}

std::string TomlParser::parse_key() {
   std::string key;
   while (cur() && !is_whitespace(cur()) && cur() != '=') {
      key += cur();
      next_char();
   }

   return key;
}

TomlDocument TomlParser::parse() {
   if (!good()) {
      // Return empty document error in file
      return TomlDocument();
   }

   // The final document
   TomlDocument doc;

   std::string cur_group;

   // Find next non-whitespace character
   while (skip_whitespace_and_comments(), cur()) {
      if(cur() == '[') {
         // Key group (it's not an array as an array is always a value)
         cur_group = parse_key_group() + ".";
      } else {
         std::string key = cur_group + parse_key();
         advance('='); skip_whitespace();

         std::shared_ptr<TomlValue> value = parse_value();
         if (value) {
            // We check all the prefix key groups to ensure that they haven't
            // already been defined previously
            size_t dot_pos = 0;
            while (dot_pos = key.find(".", dot_pos + 1), dot_pos != std::string::npos) {
               std::string key_group(key, 0, dot_pos);
               if(doc.is_key(key_group)) {
                  error("The key '%s' has already been used", key_group.c_str());
                  break;
               }
            }

            // Now check the whole key
            if (!doc.is_key(key)) {
               if (success())
                  doc.insert(key, value);
            } else {
               error("The key '%s' has already been used", key.c_str());
            }
         }
      }
   }

   this->close();

   return doc;
}

bool TomlParser::good() const {
   return source_file_.good();
}

bool TomlParser::success() const {
   return errors_.size() == 0;
}

bool TomlParser::open(const std::string filename) {
   source_file_.open(filename);
   cur_ = new char(' '); // Dummy value

   return source_file_.good();
}

void TomlParser::close() {
    source_file_.close();
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include "vbucket.hh"
#include "ep_engine.h"
#include "ep.hh"
#include "backfill.hh"

static bool isMemoryUsageTooHigh(EPStats &stats) {
    double memoryUsed = static_cast<double>(stats.getTotalMemoryUsed());
    double maxSize = static_cast<double>(stats.getMaxDataSize());
    return memoryUsed > (maxSize * BACKFILL_MEM_THRESHOLD);
}

/**
 * Callback class used to process an item backfilled from disk and push it into
 * the corresponding TAP queue.
 */
class BackfillDiskCallback : public Callback<GetValue> {
public:
    BackfillDiskCallback(hrtime_t token, const std::string &n,
                         TapConnMap &tcm, EventuallyPersistentEngine* e)
        : connToken(token), tapConnName(n), connMap(tcm), engine(e) {
        assert(engine);
    }

    void callback(GetValue &val);

private:

    hrtime_t                    connToken;
    const std::string           tapConnName;
    TapConnMap                 &connMap;
    EventuallyPersistentEngine *engine;
};

void BackfillDiskCallback::callback(GetValue &gv) {
    assert(gv.getValue());
    CompletedBGFetchTapOperation tapop(connToken, gv.getValue()->getVBucketId(), true);
    // if the tap connection is closed, then free an Item instance
    if (!connMap.performTapOp(tapConnName, tapop, gv.getValue())) {
        delete gv.getValue();
    }
}

bool BackfillDiskLoad::callback(Dispatcher &d, TaskId &t) {
    if (isMemoryUsageTooHigh(engine->getEpStats())) {
        LOG(EXTENSION_LOG_INFO, "VBucket %d backfill task from disk is "
            "temporarily suspended  because the current memory usage is too high",
            vbucket);
        d.snooze(t, 1);
        return true;
    }

    if (connMap.checkConnectivity(name) && !engine->getEpStore()->isFlushAllScheduled()) {
        shared_ptr<Callback<GetValue> > backfill_cb(new BackfillDiskCallback(connToken,
                                                                             name, connMap,
                                                                             engine));
        if (backfillType == ALL_MUTATIONS) {
            store->dump(vbucket, backfill_cb);
        } else if (store->getStorageProperties().hasPersistedDeletions() &&
                   backfillType == DELETIONS_ONLY) {
            store->dumpDeleted(vbucket, backfill_cb);
        } else {
            LOG(EXTENSION_LOG_WARNING,
                "Underlying KVStore doesn't support this kind of backfill");
            abort();
        }
    }

    LOG(EXTENSION_LOG_INFO,"VBucket %d backfill task from disk is completed",
        vbucket);

    // Should decr the disk backfill counter regardless of the connectivity status
    CompleteDiskBackfillTapOperation op;
    connMap.performTapOp(name, op, static_cast<void*>(NULL));

    return false;
}

std::string BackfillDiskLoad::description() {
    std::stringstream rv;
    rv << "Loading TAP backfill from disk for vb " << vbucket;
    return rv.str();
}

bool BackFillVisitor::visitBucket(RCPtr<VBucket> &vb) {
    apply();

    if (vBucketFilter(vb->getId())) {
        // When the backfill is scheduled for a given vbucket, set the TAP cursor to
        // the beginning of the open checkpoint.
        engine->tapConnMap->SetCursorToOpenCheckpoint(name, vb->getId());

        VBucketVisitor::visitBucket(vb);
        double num_items = static_cast<double>(vb->ht.getNumItems());
        double num_non_resident = static_cast<double>(vb->ht.getNumNonResidentItems());
        size_t num_backfill_items = 0;

        if (num_items == 0) {
            return false;
        }

        double resident_threshold = engine->getTapConfig().getBackfillResidentThreshold();
        residentRatioBelowThreshold =
            ((num_items - num_non_resident) / num_items) < resident_threshold ? true : false;

        if (efficientVBDump && residentRatioBelowThreshold) {
            // disk backfill for persisted items + memory backfill for resident items
            num_backfill_items = (vb->opsCreate - vb->opsDelete) +
                static_cast<size_t>(num_items - num_non_resident);
            vbuckets[vb->getId()] = ALL_MUTATIONS;
            ScheduleDiskBackfillTapOperation tapop;
            engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
        } else {
            if (engine->epstore->getStorageProperties().hasPersistedDeletions()) {
                vbuckets[vb->getId()] = DELETIONS_ONLY;
                ScheduleDiskBackfillTapOperation tapop;
                engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
            }
            num_backfill_items = static_cast<size_t>(num_items);
        }

        engine->tapConnMap->incrBackfillRemaining(name, num_backfill_items);
        return true;
    }
    return false;
}

void BackFillVisitor::visit(StoredValue *v) {
    // If efficient VBdump is supported and an item is not resident,
    // skip the item as it will be fetched by the disk backfill.
    if (efficientVBDump && residentRatioBelowThreshold && !v->isResident()) {
        return;
    }

    if (v->isTempItem()) {
        return;
    }

    queued_item qi(new QueuedItem(v->getKey(), currentBucket->getId(), queue_op_set));
    queue->push_back(qi);
}

void BackFillVisitor::apply(void) {
    // If efficient VBdump is supported, schedule all the disk backfill tasks.
    if (efficientVBDump) {
        std::map<uint16_t, backfill_t>::iterator it = vbuckets.begin();
        for (; it != vbuckets.end(); it++) {
            Dispatcher *d(engine->epstore->getAuxIODispatcher());
            KVStore *underlying(engine->epstore->getAuxUnderlying());
            assert(d);
            LOG(EXTENSION_LOG_INFO,
                "Schedule a full backfill from disk for vbucket %d.\n",
                it->first);
            shared_ptr<DispatcherCallback> cb(new BackfillDiskLoad(name,
                                                                   engine,
                                                                   *engine->tapConnMap,
                                                                   underlying,
                                                                   it->first,
                                                                   it->second,
                                                                   connToken));
            d->schedule(cb, NULL, Priority::TapBgFetcherPriority);
        }
        vbuckets.clear();
    }

    setEvents();
}

void BackFillVisitor::setEvents() {
    if (checkValidity()) {
        if (!queue->empty()) {
            engine->tapConnMap->setEvents(name, queue);
        }
    }
}

bool BackFillVisitor::pauseVisitor() {
    bool pause(true);

    ssize_t theSize(engine->tapConnMap->backfillQueueDepth(name));
    if (!checkValidity() || theSize < 0) {
        LOG(EXTENSION_LOG_WARNING, "TapProducer %s went away. Stopping backfill",
            name.c_str());
        valid = false;
        return false;
    }

    ssize_t maxBackfillSize = engine->getTapConfig().getBackfillBacklogLimit();
    pause = theSize > maxBackfillSize;

    if (pause) {
        LOG(EXTENSION_LOG_INFO, "Tap queue depth is too big for %s!!! ",
            "Pausing backfill temporarily...\n", name.c_str());
    }
    return pause;
}

void BackFillVisitor::complete() {
    apply();
    CompleteBackfillTapOperation tapop;
    engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
    LOG(EXTENSION_LOG_INFO,
        "Backfill dispatcher task for TapProducer %s is completed.\n",
        name.c_str());
}

bool BackFillVisitor::checkValidity() {
    if (valid) {
        valid = engine->tapConnMap->checkConnectivity(name);
        if (!valid) {
            LOG(EXTENSION_LOG_WARNING, "Backfilling connectivity for %s went "
                "invalid. Stopping backfill.\n", name.c_str());
        }
    }
    return valid;
}

bool BackfillTask::callback(Dispatcher &d, TaskId &t) {
    (void) t;
    engine->getEpStore()->visit(bfv, "Backfill task", &d,
                                Priority::BackfillTaskPriority, true, 1);
    return false;
}
<commit_msg>MB-8024: Fix to the BackfillRemaining stat overflow<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include "vbucket.hh"
#include "ep_engine.h"
#include "ep.hh"
#include "backfill.hh"

static bool isMemoryUsageTooHigh(EPStats &stats) {
    double memoryUsed = static_cast<double>(stats.getTotalMemoryUsed());
    double maxSize = static_cast<double>(stats.getMaxDataSize());
    return memoryUsed > (maxSize * BACKFILL_MEM_THRESHOLD);
}

/**
 * Callback class used to process an item backfilled from disk and push it into
 * the corresponding TAP queue.
 */
class BackfillDiskCallback : public Callback<GetValue> {
public:
    BackfillDiskCallback(hrtime_t token, const std::string &n,
                         TapConnMap &tcm, EventuallyPersistentEngine* e)
        : connToken(token), tapConnName(n), connMap(tcm), engine(e) {
        assert(engine);
    }

    void callback(GetValue &val);

private:

    hrtime_t                    connToken;
    const std::string           tapConnName;
    TapConnMap                 &connMap;
    EventuallyPersistentEngine *engine;
};

void BackfillDiskCallback::callback(GetValue &gv) {
    assert(gv.getValue());
    CompletedBGFetchTapOperation tapop(connToken, gv.getValue()->getVBucketId(), true);
    // if the tap connection is closed, then free an Item instance
    if (!connMap.performTapOp(tapConnName, tapop, gv.getValue())) {
        delete gv.getValue();
    }
}

bool BackfillDiskLoad::callback(Dispatcher &d, TaskId &t) {
    if (isMemoryUsageTooHigh(engine->getEpStats())) {
        LOG(EXTENSION_LOG_INFO, "VBucket %d backfill task from disk is "
            "temporarily suspended  because the current memory usage is too high",
            vbucket);
        d.snooze(t, 1);
        return true;
    }

    if (connMap.checkConnectivity(name) && !engine->getEpStore()->isFlushAllScheduled()) {
        shared_ptr<Callback<GetValue> > backfill_cb(new BackfillDiskCallback(connToken,
                                                                             name, connMap,
                                                                             engine));
        if (backfillType == ALL_MUTATIONS) {
            store->dump(vbucket, backfill_cb);
        } else if (store->getStorageProperties().hasPersistedDeletions() &&
                   backfillType == DELETIONS_ONLY) {
            store->dumpDeleted(vbucket, backfill_cb);
        } else {
            LOG(EXTENSION_LOG_WARNING,
                "Underlying KVStore doesn't support this kind of backfill");
            abort();
        }
    }

    LOG(EXTENSION_LOG_INFO,"VBucket %d backfill task from disk is completed",
        vbucket);

    // Should decr the disk backfill counter regardless of the connectivity status
    CompleteDiskBackfillTapOperation op;
    connMap.performTapOp(name, op, static_cast<void*>(NULL));

    return false;
}

std::string BackfillDiskLoad::description() {
    std::stringstream rv;
    rv << "Loading TAP backfill from disk for vb " << vbucket;
    return rv.str();
}

bool BackFillVisitor::visitBucket(RCPtr<VBucket> &vb) {
    apply();

    if (vBucketFilter(vb->getId())) {
        // When the backfill is scheduled for a given vbucket, set the TAP cursor to
        // the beginning of the open checkpoint.
        engine->tapConnMap->SetCursorToOpenCheckpoint(name, vb->getId());

        VBucketVisitor::visitBucket(vb);
        double num_items = static_cast<double>(vb->ht.getNumItems());
        double num_non_resident = static_cast<double>(vb->ht.getNumNonResidentItems());
        double num_res_items = 0;
        size_t num_backfill_items = 0;

        if (num_items == 0) {
            return false;
        }
        if (num_items > num_non_resident) {
            num_res_items = num_items - num_non_resident;
        }

        double resident_threshold = engine->getTapConfig().getBackfillResidentThreshold();
        residentRatioBelowThreshold =
            (num_res_items / num_items) < resident_threshold ? true : false;

        if (efficientVBDump && residentRatioBelowThreshold) {
            // disk backfill for persisted items + memory backfill for resident items
            size_t num_create = vb->opsCreate;
            size_t num_delete = vb->opsDelete;
            size_t persisted_items = 0;
            if (num_create > num_delete) {
                persisted_items = num_create - num_delete;
            }
            num_backfill_items = persisted_items + static_cast<size_t>(num_res_items);
            vbuckets[vb->getId()] = ALL_MUTATIONS;
            ScheduleDiskBackfillTapOperation tapop;
            engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
        } else {
            if (engine->epstore->getStorageProperties().hasPersistedDeletions()) {
                vbuckets[vb->getId()] = DELETIONS_ONLY;
                ScheduleDiskBackfillTapOperation tapop;
                engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
            }
            num_backfill_items = static_cast<size_t>(num_items);
        }

        engine->tapConnMap->incrBackfillRemaining(name, num_backfill_items);
        return true;
    }
    return false;
}

void BackFillVisitor::visit(StoredValue *v) {
    // If efficient VBdump is supported and an item is not resident,
    // skip the item as it will be fetched by the disk backfill.
    if (efficientVBDump && residentRatioBelowThreshold && !v->isResident()) {
        return;
    }

    if (v->isTempItem()) {
        return;
    }

    queued_item qi(new QueuedItem(v->getKey(), currentBucket->getId(), queue_op_set));
    queue->push_back(qi);
}

void BackFillVisitor::apply(void) {
    // If efficient VBdump is supported, schedule all the disk backfill tasks.
    if (efficientVBDump) {
        std::map<uint16_t, backfill_t>::iterator it = vbuckets.begin();
        for (; it != vbuckets.end(); it++) {
            Dispatcher *d(engine->epstore->getAuxIODispatcher());
            KVStore *underlying(engine->epstore->getAuxUnderlying());
            assert(d);
            LOG(EXTENSION_LOG_INFO,
                "Schedule a full backfill from disk for vbucket %d.\n",
                it->first);
            shared_ptr<DispatcherCallback> cb(new BackfillDiskLoad(name,
                                                                   engine,
                                                                   *engine->tapConnMap,
                                                                   underlying,
                                                                   it->first,
                                                                   it->second,
                                                                   connToken));
            d->schedule(cb, NULL, Priority::TapBgFetcherPriority);
        }
        vbuckets.clear();
    }

    setEvents();
}

void BackFillVisitor::setEvents() {
    if (checkValidity()) {
        if (!queue->empty()) {
            engine->tapConnMap->setEvents(name, queue);
        }
    }
}

bool BackFillVisitor::pauseVisitor() {
    bool pause(true);

    ssize_t theSize(engine->tapConnMap->backfillQueueDepth(name));
    if (!checkValidity() || theSize < 0) {
        LOG(EXTENSION_LOG_WARNING, "TapProducer %s went away. Stopping backfill",
            name.c_str());
        valid = false;
        return false;
    }

    ssize_t maxBackfillSize = engine->getTapConfig().getBackfillBacklogLimit();
    pause = theSize > maxBackfillSize;

    if (pause) {
        LOG(EXTENSION_LOG_INFO, "Tap queue depth is too big for %s!!! ",
            "Pausing backfill temporarily...\n", name.c_str());
    }
    return pause;
}

void BackFillVisitor::complete() {
    apply();
    CompleteBackfillTapOperation tapop;
    engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
    LOG(EXTENSION_LOG_INFO,
        "Backfill dispatcher task for TapProducer %s is completed.\n",
        name.c_str());
}

bool BackFillVisitor::checkValidity() {
    if (valid) {
        valid = engine->tapConnMap->checkConnectivity(name);
        if (!valid) {
            LOG(EXTENSION_LOG_WARNING, "Backfilling connectivity for %s went "
                "invalid. Stopping backfill.\n", name.c_str());
        }
    }
    return valid;
}

bool BackfillTask::callback(Dispatcher &d, TaskId &t) {
    (void) t;
    engine->getEpStore()->visit(bfv, "Backfill task", &d,
                                Priority::BackfillTaskPriority, true, 1);
    return false;
}
<|endoftext|>