<commit_before>// Scintilla source code edit control
/** @file LexEiffel.cxx
 ** Lexer for Eiffel.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

inline bool isEiffelOperator(unsigned int ch) {
	// '.' left out as it is used to make up numbers
	return ch == '*' || ch == '/' || ch == '\\' || ch == '-' || ch == '+' ||
	        ch == '(' || ch == ')' || ch == '=' ||
	        ch == '{' || ch == '}' || ch == '~' ||
	        ch == '[' || ch == ']' || ch == ';' ||
	        ch == '<' || ch == '>' || ch == ',' ||
	        ch == '.' || ch == '^' || ch == '%' || ch == ':' ||
		ch == '!' || ch == '@' || ch == '?';
}

static void getRangeLowered(unsigned int start,
		unsigned int end,
		Accessor &styler,
		char *s,
		unsigned int len) {
	unsigned int i = 0;
	while ((i < end - start + 1) && (i < len-1)) {
		s[i] = static_cast<char>(tolower(styler[start + i]));
		i++;
	}
	s[i] = '\0';
}

inline bool IsASpace(unsigned int ch) {
    return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
}

inline bool IsAWordChar(unsigned int  ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(unsigned int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool IsADigit(unsigned int ch) {
	return (ch >= '0') && (ch <= '9');
}

// All languages handled so far can treat all characters >= 0x80 as one class
// which just continues the current token or starts an identifier if in default.
// DBCS treated specially as the second character can be < 0x80 and hence
// syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80
class ColouriseContext {
	Accessor &styler;
	int lengthDoc;
	int currentPos;
	ColouriseContext& operator=(const ColouriseContext&) {
		return *this;
	}
public:
	int state;
	unsigned int chPrev;
	unsigned int ch;
	unsigned int chNext;

	ColouriseContext(unsigned int startPos, int length,
                        int initStyle, Accessor &styler_) :
		styler(styler_),
		lengthDoc(startPos + length),
		currentPos(startPos),
		state(initStyle),
		chPrev(0),
		ch(0),
		chNext(0) {
		styler.StartAt(startPos);
		styler.StartSegment(startPos);
		int pos = currentPos;
		ch = static_cast<unsigned char>(styler.SafeGetCharAt(pos));
		if (styler.IsLeadByte(static_cast<char>(ch))) {
			pos++;
			ch = ch << 8;
			ch |= static_cast<unsigned char>(styler.SafeGetCharAt(pos));
		}
		chNext = static_cast<unsigned char>(styler.SafeGetCharAt(pos+1));
		if (styler.IsLeadByte(static_cast<char>(chNext))) {
			chNext = chNext << 8;
			chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(pos+2));
		}
	}
	void Complete() {
		styler.ColourTo(currentPos - 1, state);
	}
	bool More() {
		return currentPos <= lengthDoc;
	}
	void Forward() {
		chPrev = ch;
		currentPos++;
		if (ch >= 0x100)
			currentPos++;
		ch = chNext;
		chNext = static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+1));
		if (styler.IsLeadByte(static_cast<char>(chNext))) {
			chNext = chNext << 8;
			chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(currentPos + 2));
		}
	}
	void ChangeState(int state_) {
		state = state_;
	}
	void SetState(int state_) {
		styler.ColourTo(currentPos - 1, state);
		state = state_;
	}
	void GetCurrentLowered(char *s, int len) {
		getRangeLowered(styler.GetStartSegment(), currentPos - 1, styler, s, len);
	}
};

static void ColouriseEiffelDoc(unsigned int startPos,
                            int length,
                            int initStyle,
                            WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	ColouriseContext lc(startPos, length, initStyle, styler);

	for (; lc.More(); lc.Forward()) {

		if (lc.state == SCE_EIFFEL_STRINGEOL) {
			if (lc.ch != '\r' && lc.ch != '\n') {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_OPERATOR) {
			lc.SetState(SCE_EIFFEL_DEFAULT);
		} else if (lc.state == SCE_EIFFEL_WORD) {
			if (!IsAWordChar(lc.ch)) {
				char s[100];
				lc.GetCurrentLowered(s, sizeof(s));
				if (!keywords.InList(s)) {
					lc.ChangeState(SCE_EIFFEL_IDENTIFIER);
				}
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_NUMBER) {
			if (!IsAWordChar(lc.ch)) {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_COMMENTLINE) {
			if (lc.ch == '\r' || lc.ch == '\n') {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_STRING) {
			if (lc.ch == '%') {
				lc.Forward();
			} else if (lc.ch == '\"') {
				lc.Forward();
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_CHARACTER) {
			if (lc.ch == '\r' || lc.ch == '\n') {
				lc.SetState(SCE_EIFFEL_STRINGEOL);
			} else if (lc.ch == '%') {
				lc.Forward();
			} else if (lc.ch == '\'') {
				lc.Forward();
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		}

		if (lc.state == SCE_EIFFEL_DEFAULT) {
			if (lc.ch == '-' && lc.chNext == '-') {
				lc.SetState(SCE_EIFFEL_COMMENTLINE);
			} else if (lc.ch == '\"') {
				lc.SetState(SCE_EIFFEL_STRING);
			} else if (lc.ch == '\'') {
				lc.SetState(SCE_EIFFEL_CHARACTER);
			} else if (IsADigit(lc.ch) || (lc.ch == '.')) {
				lc.SetState(SCE_EIFFEL_NUMBER);
			} else if (IsAWordStart(lc.ch)) {
				lc.SetState(SCE_EIFFEL_WORD);
			} else if (isEiffelOperator(lc.ch)) {
				lc.SetState(SCE_EIFFEL_OPERATOR);
			}
		}
	}
	lc.Complete();
}

static bool IsEiffelComment(Accessor &styler, int pos, int len) {
	return len>1 && styler[pos]=='-' && styler[pos+1]=='-';
}

static void FoldEiffelDocIndent(unsigned int startPos, int length, int,
						   WordList *[], Accessor &styler) {
	int lengthDoc = startPos + length;

	// Backtrack to previous line in case need to fix its fold status
	int lineCurrent = styler.GetLine(startPos);
	if (startPos > 0) {
		if (lineCurrent > 0) {
			lineCurrent--;
			startPos = styler.LineStart(lineCurrent);
		}
	}
	int spaceFlags = 0;
	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsEiffelComment);
	char chNext = styler[startPos];
	for (int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) {
			int lev = indentCurrent;
			int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsEiffelComment);
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
					// Line after is blank so check the next - maybe should continue further?
					int spaceFlags2 = 0;
					int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsEiffelComment);
					if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
						lev |= SC_FOLDLEVELHEADERFLAG;
					}
				}
			}
			indentCurrent = indentNext;
			styler.SetLevel(lineCurrent, lev);
			lineCurrent++;
		}
	}
}

static void FoldEiffelDocKeyWords(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int stylePrev = 0;
	int styleNext = styler.StyleAt(startPos);
	// lastDeferred should be determined by looking back to last keyword in case
	// the "deferred" is on a line before "class"
	bool lastDeferred = false;
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if ((stylePrev != SCE_EIFFEL_WORD) && (style == SCE_EIFFEL_WORD)) {
			char s[20];
			unsigned int j = 0;
			while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) {
				s[j] = styler[i + j];
				j++;
			}
			s[j] = '\0';

			if (
				(strcmp(s, "check") == 0) ||
				(strcmp(s, "debug") == 0) ||
				(strcmp(s, "deferred") == 0) ||
				(strcmp(s, "do") == 0) ||
				(strcmp(s, "from") == 0) ||
				(strcmp(s, "if") == 0) ||
				(strcmp(s, "inspect") == 0) ||
				(strcmp(s, "once") == 0)
			)
				levelCurrent++;
			if (!lastDeferred && (strcmp(s, "class") == 0))
				levelCurrent++;
			if (strcmp(s, "end") == 0)
				levelCurrent--;
			lastDeferred = strcmp(s, "deferred") == 0;
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
		stylePrev = style;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

LexerModule lmEiffel(SCLEX_EIFFEL, ColouriseEiffelDoc, "eiffel", FoldEiffelDocIndent);
LexerModule lmEiffelkw(SCLEX_EIFFELKW, ColouriseEiffelDoc, "eiffelkw", FoldEiffelDocKeyWords);
<commit_msg>Changed name of ColouriseContext to allow debugging.<commit_after>// Scintilla source code edit control
/** @file LexEiffel.cxx
 ** Lexer for Eiffel.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

inline bool isEiffelOperator(unsigned int ch) {
	// '.' left out as it is used to make up numbers
	return ch == '*' || ch == '/' || ch == '\\' || ch == '-' || ch == '+' ||
	        ch == '(' || ch == ')' || ch == '=' ||
	        ch == '{' || ch == '}' || ch == '~' ||
	        ch == '[' || ch == ']' || ch == ';' ||
	        ch == '<' || ch == '>' || ch == ',' ||
	        ch == '.' || ch == '^' || ch == '%' || ch == ':' ||
		ch == '!' || ch == '@' || ch == '?';
}

static void getRangeLowered(unsigned int start,
		unsigned int end,
		Accessor &styler,
		char *s,
		unsigned int len) {
	unsigned int i = 0;
	while ((i < end - start + 1) && (i < len-1)) {
		s[i] = static_cast<char>(tolower(styler[start + i]));
		i++;
	}
	s[i] = '\0';
}

inline bool IsASpace(unsigned int ch) {
    return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
}

inline bool IsAWordChar(unsigned int  ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(unsigned int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool IsADigit(unsigned int ch) {
	return (ch >= '0') && (ch <= '9');
}

// All languages handled so far can treat all characters >= 0x80 as one class
// which just continues the current token or starts an identifier if in default.
// DBCS treated specially as the second character can be < 0x80 and hence
// syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80
class xColouriseContext {
	Accessor &styler;
	int lengthDoc;
	int currentPos;
	xColouriseContext& operator=(const xColouriseContext&) {
		return *this;
	}
public:
	int state;
	unsigned int chPrev;
	unsigned int ch;
	unsigned int chNext;

	xColouriseContext(unsigned int startPos, int length,
                        int initStyle, Accessor &styler_) :
		styler(styler_),
		lengthDoc(startPos + length),
		currentPos(startPos),
		state(initStyle),
		chPrev(0),
		ch(0),
		chNext(0) {
		styler.StartAt(startPos);
		styler.StartSegment(startPos);
		int pos = currentPos;
		ch = static_cast<unsigned char>(styler.SafeGetCharAt(pos));
		if (styler.IsLeadByte(static_cast<char>(ch))) {
			pos++;
			ch = ch << 8;
			ch |= static_cast<unsigned char>(styler.SafeGetCharAt(pos));
		}
		chNext = static_cast<unsigned char>(styler.SafeGetCharAt(pos+1));
		if (styler.IsLeadByte(static_cast<char>(chNext))) {
			chNext = chNext << 8;
			chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(pos+2));
		}
	}
	void Complete() {
		styler.ColourTo(currentPos - 1, state);
	}
	bool More() {
		return currentPos <= lengthDoc;
	}
	void Forward() {
		chPrev = ch;
		currentPos++;
		if (ch >= 0x100)
			currentPos++;
		ch = chNext;
		chNext = static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+1));
		if (styler.IsLeadByte(static_cast<char>(chNext))) {
			chNext = chNext << 8;
			chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(currentPos + 2));
		}
	}
	void ChangeState(int state_) {
		state = state_;
	}
	void SetState(int state_) {
		styler.ColourTo(currentPos - 1, state);
		state = state_;
	}
	void GetCurrentLowered(char *s, int len) {
		getRangeLowered(styler.GetStartSegment(), currentPos - 1, styler, s, len);
	}
};

static void ColouriseEiffelDoc(unsigned int startPos,
                            int length,
                            int initStyle,
                            WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	xColouriseContext lc(startPos, length, initStyle, styler);

	for (; lc.More(); lc.Forward()) {

		if (lc.state == SCE_EIFFEL_STRINGEOL) {
			if (lc.ch != '\r' && lc.ch != '\n') {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_OPERATOR) {
			lc.SetState(SCE_EIFFEL_DEFAULT);
		} else if (lc.state == SCE_EIFFEL_WORD) {
			if (!IsAWordChar(lc.ch)) {
				char s[100];
				lc.GetCurrentLowered(s, sizeof(s));
				if (!keywords.InList(s)) {
					lc.ChangeState(SCE_EIFFEL_IDENTIFIER);
				}
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_NUMBER) {
			if (!IsAWordChar(lc.ch)) {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_COMMENTLINE) {
			if (lc.ch == '\r' || lc.ch == '\n') {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_STRING) {
			if (lc.ch == '%') {
				lc.Forward();
			} else if (lc.ch == '\"') {
				lc.Forward();
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_CHARACTER) {
			if (lc.ch == '\r' || lc.ch == '\n') {
				lc.SetState(SCE_EIFFEL_STRINGEOL);
			} else if (lc.ch == '%') {
				lc.Forward();
			} else if (lc.ch == '\'') {
				lc.Forward();
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		}

		if (lc.state == SCE_EIFFEL_DEFAULT) {
			if (lc.ch == '-' && lc.chNext == '-') {
				lc.SetState(SCE_EIFFEL_COMMENTLINE);
			} else if (lc.ch == '\"') {
				lc.SetState(SCE_EIFFEL_STRING);
			} else if (lc.ch == '\'') {
				lc.SetState(SCE_EIFFEL_CHARACTER);
			} else if (IsADigit(lc.ch) || (lc.ch == '.')) {
				lc.SetState(SCE_EIFFEL_NUMBER);
			} else if (IsAWordStart(lc.ch)) {
				lc.SetState(SCE_EIFFEL_WORD);
			} else if (isEiffelOperator(lc.ch)) {
				lc.SetState(SCE_EIFFEL_OPERATOR);
			}
		}
	}
	lc.Complete();
}

static bool IsEiffelComment(Accessor &styler, int pos, int len) {
	return len>1 && styler[pos]=='-' && styler[pos+1]=='-';
}

static void FoldEiffelDocIndent(unsigned int startPos, int length, int,
						   WordList *[], Accessor &styler) {
	int lengthDoc = startPos + length;

	// Backtrack to previous line in case need to fix its fold status
	int lineCurrent = styler.GetLine(startPos);
	if (startPos > 0) {
		if (lineCurrent > 0) {
			lineCurrent--;
			startPos = styler.LineStart(lineCurrent);
		}
	}
	int spaceFlags = 0;
	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsEiffelComment);
	char chNext = styler[startPos];
	for (int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) {
			int lev = indentCurrent;
			int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsEiffelComment);
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
					// Line after is blank so check the next - maybe should continue further?
					int spaceFlags2 = 0;
					int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsEiffelComment);
					if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
						lev |= SC_FOLDLEVELHEADERFLAG;
					}
				}
			}
			indentCurrent = indentNext;
			styler.SetLevel(lineCurrent, lev);
			lineCurrent++;
		}
	}
}

static void FoldEiffelDocKeyWords(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int stylePrev = 0;
	int styleNext = styler.StyleAt(startPos);
	// lastDeferred should be determined by looking back to last keyword in case
	// the "deferred" is on a line before "class"
	bool lastDeferred = false;
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if ((stylePrev != SCE_EIFFEL_WORD) && (style == SCE_EIFFEL_WORD)) {
			char s[20];
			unsigned int j = 0;
			while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) {
				s[j] = styler[i + j];
				j++;
			}
			s[j] = '\0';

			if (
				(strcmp(s, "check") == 0) ||
				(strcmp(s, "debug") == 0) ||
				(strcmp(s, "deferred") == 0) ||
				(strcmp(s, "do") == 0) ||
				(strcmp(s, "from") == 0) ||
				(strcmp(s, "if") == 0) ||
				(strcmp(s, "inspect") == 0) ||
				(strcmp(s, "once") == 0)
			)
				levelCurrent++;
			if (!lastDeferred && (strcmp(s, "class") == 0))
				levelCurrent++;
			if (strcmp(s, "end") == 0)
				levelCurrent--;
			lastDeferred = strcmp(s, "deferred") == 0;
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
		stylePrev = style;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

LexerModule lmEiffel(SCLEX_EIFFEL, ColouriseEiffelDoc, "eiffel", FoldEiffelDocIndent);
LexerModule lmEiffelkw(SCLEX_EIFFELKW, ColouriseEiffelDoc, "eiffelkw", FoldEiffelDocKeyWords);
<|endoftext|>


<commit_before>#include "Monotonic.h"
#include "IRMutator.h"
#include "Substitute.h"
#include "Scope.h"
#include "Simplify.h"
#include "IROperator.h"

namespace Halide {
namespace Internal {

using std::string;

class MonotonicVisitor : public IRVisitor {
    const string &var;

    Scope<Monotonic> scope;

    void visit(const IntImm *) {
        result = Monotonic::Constant;
    }

    void visit(const UIntImm *) {
        result = Monotonic::Constant;
    }

    void visit(const FloatImm *) {
        result = Monotonic::Constant;
    }

    void visit(const StringImm *) {
        internal_error << "Monotonic on String\n";
    }

    void visit(const Cast *op) {
        op->value.accept(this);

        if (op->type.can_represent(op->value.type())) {
            // No overflow.
            return;
        }

        if (op->value.type().bits() >= 32 && op->type.bits() >= 32) {
            // We assume 32-bit types don't overflow.
            return;
        }

        // A narrowing cast. There may be more cases we can catch, but
        // for now we punt.
        if (result != Monotonic::Constant) {
            result = Monotonic::Unknown;
        }
    }

    void visit(const Variable *op) {
        if (op->name == var) {
            result = Monotonic::Increasing;
        } else if (scope.contains(op->name)) {
            result = scope.get(op->name);
        } else {
            result = Monotonic::Constant;
        }
    }

    Monotonic flip(Monotonic r) {
        switch (r) {
        case Monotonic::Increasing: return Monotonic::Decreasing;
        case Monotonic::Decreasing: return Monotonic::Increasing;
        default: return r;
        }
    }

    Monotonic unify(Monotonic a, Monotonic b) {
        if (a == b) {
            return a;
        }

        if (a == Monotonic::Unknown || b == Monotonic::Unknown) {
            return Monotonic::Unknown;
        }

        if (a == Monotonic::Constant) {
            return b;
        }

        if (b == Monotonic::Constant) {
            return a;
        }

        return Monotonic::Unknown;
    }

    void visit(const Add *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit(const Sub *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, flip(rb));
    }

    void visit(const Mul *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;

        if (ra == Monotonic::Constant && rb == Monotonic::Constant) {
            result = Monotonic::Constant;
        } else if (is_positive_const(op->a)) {
            result = rb;
        } else if (is_positive_const(op->b)) {
            result = ra;
        } else if (is_negative_const(op->a)) {
            result = flip(rb);
        } else if (is_negative_const(op->b)) {
            result = flip(ra);
        } else {
            result = Monotonic::Unknown;
        }

    }

    void visit(const Div *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;

        if (ra == Monotonic::Constant && rb == Monotonic::Constant) {
            result = Monotonic::Constant;
        } else if (is_positive_const(op->b)) {
            result = ra;
        } else if (is_negative_const(op->b)) {
            result = flip(ra);
        } else {
            result = Monotonic::Unknown;
        }
    }

    void visit(const Mod *op) {
        result = Monotonic::Unknown;
    }

    void visit(const Min *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit(const Max *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit_eq(Expr a, Expr b) {
        a.accept(this);
        Monotonic ra = result;
        b.accept(this);
        Monotonic rb = result;
        if (ra == Monotonic::Constant && rb == Monotonic::Constant) {
            result = Monotonic::Constant;
        } else {
            result = Monotonic::Unknown;
        }
    }

    void visit(const EQ *op) {
        visit_eq(op->a, op->b);
    }

    void visit(const NE *op) {
        visit_eq(op->a, op->b);
    }

    void visit_lt(Expr a, Expr b) {
        a.accept(this);
        Monotonic ra = result;
        b.accept(this);
        Monotonic rb = result;
        result = unify(flip(ra), rb);
    }

    void visit(const LT *op) {
        visit_lt(op->a, op->b);
    }

    void visit(const LE *op) {
        visit_lt(op->a, op->b);
    }

    void visit(const GT *op) {
        visit_lt(op->b, op->a);
    }

    void visit(const GE *op) {
        visit_lt(op->b, op->a);
    }

    void visit(const And *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit(const Or *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit(const Not *op) {
        op->a.accept(this);
        result = flip(result);
    }

    void visit(const Select *op) {
        op->condition.accept(this);
        Monotonic rcond = result;

        op->true_value.accept(this);
        Monotonic ra = result;
        op->false_value.accept(this);
        Monotonic rb = result;
        Monotonic unified = unify(ra, rb);

        if (rcond == Monotonic::Constant) {
            result = unified;
            return;
        }

        bool true_value_ge_false_value = is_one(simplify(op->true_value >= op->false_value));
        bool true_value_le_false_value = is_one(simplify(op->true_value <= op->false_value));

        bool switches_from_true_to_false = rcond == Monotonic::Decreasing;
        bool switches_from_false_to_true = rcond == Monotonic::Increasing;

        if (rcond == Monotonic::Constant) {
            result = unify(ra, rb);
        } else if ((unified == Monotonic::Increasing || unified == Monotonic::Constant) &&
                   ((switches_from_false_to_true && true_value_ge_false_value) ||
                    (switches_from_true_to_false && true_value_le_false_value))) {
            // Both paths increase, and the condition makes it switch
            // from the lesser path to the greater path.
            result = Monotonic::Increasing;
        } else if ((unified == Monotonic::Decreasing || unified == Monotonic::Constant) &&
                   ((switches_from_false_to_true && true_value_le_false_value) ||
                    (switches_from_true_to_false && true_value_ge_false_value))) {
            // Both paths decrease, and the condition makes it switch
            // from the greater path to the lesser path.
            result = Monotonic::Decreasing;
        } else {
            result = Monotonic::Unknown;
        }
    }

    void visit(const Load *op) {
        op->index.accept(this);
        if (result != Monotonic::Constant) {
            result = Monotonic::Unknown;
        }
    }

    void visit(const Ramp *op) {
        internal_error << "Monotonic of vector\n";
    }

    void visit(const Broadcast *op) {
        internal_error << "Monotonic of vector\n";
    }

    void visit(const Call *op) {
        // Some functions are known to be monotonic
        if (op->is_intrinsic(Call::likely)) {
            op->args[0].accept(this);
            return;
        }

        for (size_t i = 0; i < op->args.size(); i++) {
            op->args[i].accept(this);
            if (result != Monotonic::Constant) {
                result = Monotonic::Unknown;
                return;
            }
        }
        result = Monotonic::Constant;
    }

    void visit(const Let *op) {
        op->value.accept(this);

        if (result == Monotonic::Constant) {
            // No point pushing it if it's constant w.r.t the var,
            // because unknown variables are treated as constant.
            op->body.accept(this);
        } else {
            scope.push(op->name, result);
            op->body.accept(this);
            scope.pop(op->name);
        }
    }

    void visit(const LetStmt *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const AssertStmt *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const ProducerConsumer *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const For *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Store *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Provide *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Allocate *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Free *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Realize *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Block *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const IfThenElse *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Evaluate *op) {
        internal_error << "Monotonic of statement\n";
    }

public:
    Monotonic result;

    MonotonicVisitor(const std::string &v) : var(v), result(Monotonic::Unknown) {}
};

Monotonic is_monotonic(Expr e, const std::string &var) {
    if (!e.defined()) return Monotonic::Unknown;
    MonotonicVisitor m(var);
    e.accept(&m);
    return m.result;
}

namespace {
void check_increasing(Expr e) {
    internal_assert(is_monotonic(e, "x") == Monotonic::Increasing)
        << "Was supposed to be increasing: " << e << "\n";
}

void check_decreasing(Expr e) {
    internal_assert(is_monotonic(e, "x") == Monotonic::Decreasing)
        << "Was supposed to be decreasing: " << e << "\n";
}

void check_constant(Expr e) {
    internal_assert(is_monotonic(e, "x") == Monotonic::Constant)
        << "Was supposed to be constant: " << e << "\n";
}

void check_unknown(Expr e) {
    internal_assert(is_monotonic(e, "x") == Monotonic::Unknown)
        << "Was supposed to be unknown: " << e << "\n";
}
}

void is_monotonic_test() {

    Expr x = Variable::make(Int(32), "x");
    Expr y = Variable::make(Int(32), "y");

    check_increasing(x);
    check_increasing(x+4);
    check_increasing(x+y);
    check_increasing(x*4);
    check_increasing(min(x+4, y+4));
    check_increasing(max(x+y, x-y));
    check_increasing(x >= y);
    check_increasing(x > y);

    check_decreasing(-x);
    check_decreasing(x*-4);
    check_decreasing(y - x);
    check_decreasing(x < y);
    check_decreasing(x <= y);

    check_unknown(x == y);
    check_unknown(x != y);
    check_unknown(x*y);

    check_increasing(select(y == 2, x, x+4));
    check_decreasing(select(y == 2, -x, x*-4));

    check_increasing(select(x > 2, x+1, x));
    check_increasing(select(x < 2, x, x+1));
    check_decreasing(select(x > 2, -x-1, -x));
    check_decreasing(select(x < 2, -x, -x-1));

    check_unknown(select(x < 2, x, x-5));
    check_unknown(select(x > 2, x-5, x));

    check_constant(y);

    check_increasing(select(x < 17, y, y+1));
    check_increasing(select(x > 17, y, y-1));
    check_decreasing(select(x < 17, y, y-1));
    check_decreasing(select(x > 17, y, y+1));

    check_constant(select(y > 3, y + 23, y - 65));

    std::cout << "is_monotonic test passed" << std::endl;
}

}
}
<commit_msg>Delete dead code<commit_after>#include "Monotonic.h"
#include "IRMutator.h"
#include "Substitute.h"
#include "Scope.h"
#include "Simplify.h"
#include "IROperator.h"

namespace Halide {
namespace Internal {

using std::string;

class MonotonicVisitor : public IRVisitor {
    const string &var;

    Scope<Monotonic> scope;

    void visit(const IntImm *) {
        result = Monotonic::Constant;
    }

    void visit(const UIntImm *) {
        result = Monotonic::Constant;
    }

    void visit(const FloatImm *) {
        result = Monotonic::Constant;
    }

    void visit(const StringImm *) {
        internal_error << "Monotonic on String\n";
    }

    void visit(const Cast *op) {
        op->value.accept(this);

        if (op->type.can_represent(op->value.type())) {
            // No overflow.
            return;
        }

        if (op->value.type().bits() >= 32 && op->type.bits() >= 32) {
            // We assume 32-bit types don't overflow.
            return;
        }

        // A narrowing cast. There may be more cases we can catch, but
        // for now we punt.
        if (result != Monotonic::Constant) {
            result = Monotonic::Unknown;
        }
    }

    void visit(const Variable *op) {
        if (op->name == var) {
            result = Monotonic::Increasing;
        } else if (scope.contains(op->name)) {
            result = scope.get(op->name);
        } else {
            result = Monotonic::Constant;
        }
    }

    Monotonic flip(Monotonic r) {
        switch (r) {
        case Monotonic::Increasing: return Monotonic::Decreasing;
        case Monotonic::Decreasing: return Monotonic::Increasing;
        default: return r;
        }
    }

    Monotonic unify(Monotonic a, Monotonic b) {
        if (a == b) {
            return a;
        }

        if (a == Monotonic::Unknown || b == Monotonic::Unknown) {
            return Monotonic::Unknown;
        }

        if (a == Monotonic::Constant) {
            return b;
        }

        if (b == Monotonic::Constant) {
            return a;
        }

        return Monotonic::Unknown;
    }

    void visit(const Add *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit(const Sub *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, flip(rb));
    }

    void visit(const Mul *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;

        if (ra == Monotonic::Constant && rb == Monotonic::Constant) {
            result = Monotonic::Constant;
        } else if (is_positive_const(op->a)) {
            result = rb;
        } else if (is_positive_const(op->b)) {
            result = ra;
        } else if (is_negative_const(op->a)) {
            result = flip(rb);
        } else if (is_negative_const(op->b)) {
            result = flip(ra);
        } else {
            result = Monotonic::Unknown;
        }

    }

    void visit(const Div *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;

        if (ra == Monotonic::Constant && rb == Monotonic::Constant) {
            result = Monotonic::Constant;
        } else if (is_positive_const(op->b)) {
            result = ra;
        } else if (is_negative_const(op->b)) {
            result = flip(ra);
        } else {
            result = Monotonic::Unknown;
        }
    }

    void visit(const Mod *op) {
        result = Monotonic::Unknown;
    }

    void visit(const Min *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit(const Max *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit_eq(Expr a, Expr b) {
        a.accept(this);
        Monotonic ra = result;
        b.accept(this);
        Monotonic rb = result;
        if (ra == Monotonic::Constant && rb == Monotonic::Constant) {
            result = Monotonic::Constant;
        } else {
            result = Monotonic::Unknown;
        }
    }

    void visit(const EQ *op) {
        visit_eq(op->a, op->b);
    }

    void visit(const NE *op) {
        visit_eq(op->a, op->b);
    }

    void visit_lt(Expr a, Expr b) {
        a.accept(this);
        Monotonic ra = result;
        b.accept(this);
        Monotonic rb = result;
        result = unify(flip(ra), rb);
    }

    void visit(const LT *op) {
        visit_lt(op->a, op->b);
    }

    void visit(const LE *op) {
        visit_lt(op->a, op->b);
    }

    void visit(const GT *op) {
        visit_lt(op->b, op->a);
    }

    void visit(const GE *op) {
        visit_lt(op->b, op->a);
    }

    void visit(const And *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit(const Or *op) {
        op->a.accept(this);
        Monotonic ra = result;
        op->b.accept(this);
        Monotonic rb = result;
        result = unify(ra, rb);
    }

    void visit(const Not *op) {
        op->a.accept(this);
        result = flip(result);
    }

    void visit(const Select *op) {
        op->condition.accept(this);
        Monotonic rcond = result;

        op->true_value.accept(this);
        Monotonic ra = result;
        op->false_value.accept(this);
        Monotonic rb = result;
        Monotonic unified = unify(ra, rb);

        if (rcond == Monotonic::Constant) {
            result = unified;
            return;
        }

        bool true_value_ge_false_value = is_one(simplify(op->true_value >= op->false_value));
        bool true_value_le_false_value = is_one(simplify(op->true_value <= op->false_value));

        bool switches_from_true_to_false = rcond == Monotonic::Decreasing;
        bool switches_from_false_to_true = rcond == Monotonic::Increasing;

        if ((unified == Monotonic::Increasing || unified == Monotonic::Constant) &&
            ((switches_from_false_to_true && true_value_ge_false_value) ||
             (switches_from_true_to_false && true_value_le_false_value))) {
            // Both paths increase, and the condition makes it switch
            // from the lesser path to the greater path.
            result = Monotonic::Increasing;
        } else if ((unified == Monotonic::Decreasing || unified == Monotonic::Constant) &&
                   ((switches_from_false_to_true && true_value_le_false_value) ||
                    (switches_from_true_to_false && true_value_ge_false_value))) {
            // Both paths decrease, and the condition makes it switch
            // from the greater path to the lesser path.
            result = Monotonic::Decreasing;
        } else {
            result = Monotonic::Unknown;
        }
    }

    void visit(const Load *op) {
        op->index.accept(this);
        if (result != Monotonic::Constant) {
            result = Monotonic::Unknown;
        }
    }

    void visit(const Ramp *op) {
        internal_error << "Monotonic of vector\n";
    }

    void visit(const Broadcast *op) {
        internal_error << "Monotonic of vector\n";
    }

    void visit(const Call *op) {
        // Some functions are known to be monotonic
        if (op->is_intrinsic(Call::likely)) {
            op->args[0].accept(this);
            return;
        }

        for (size_t i = 0; i < op->args.size(); i++) {
            op->args[i].accept(this);
            if (result != Monotonic::Constant) {
                result = Monotonic::Unknown;
                return;
            }
        }
        result = Monotonic::Constant;
    }

    void visit(const Let *op) {
        op->value.accept(this);

        if (result == Monotonic::Constant) {
            // No point pushing it if it's constant w.r.t the var,
            // because unknown variables are treated as constant.
            op->body.accept(this);
        } else {
            scope.push(op->name, result);
            op->body.accept(this);
            scope.pop(op->name);
        }
    }

    void visit(const LetStmt *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const AssertStmt *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const ProducerConsumer *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const For *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Store *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Provide *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Allocate *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Free *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Realize *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Block *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const IfThenElse *op) {
        internal_error << "Monotonic of statement\n";
    }

    void visit(const Evaluate *op) {
        internal_error << "Monotonic of statement\n";
    }

public:
    Monotonic result;

    MonotonicVisitor(const std::string &v) : var(v), result(Monotonic::Unknown) {}
};

Monotonic is_monotonic(Expr e, const std::string &var) {
    if (!e.defined()) return Monotonic::Unknown;
    MonotonicVisitor m(var);
    e.accept(&m);
    return m.result;
}

namespace {
void check_increasing(Expr e) {
    internal_assert(is_monotonic(e, "x") == Monotonic::Increasing)
        << "Was supposed to be increasing: " << e << "\n";
}

void check_decreasing(Expr e) {
    internal_assert(is_monotonic(e, "x") == Monotonic::Decreasing)
        << "Was supposed to be decreasing: " << e << "\n";
}

void check_constant(Expr e) {
    internal_assert(is_monotonic(e, "x") == Monotonic::Constant)
        << "Was supposed to be constant: " << e << "\n";
}

void check_unknown(Expr e) {
    internal_assert(is_monotonic(e, "x") == Monotonic::Unknown)
        << "Was supposed to be unknown: " << e << "\n";
}
}

void is_monotonic_test() {

    Expr x = Variable::make(Int(32), "x");
    Expr y = Variable::make(Int(32), "y");

    check_increasing(x);
    check_increasing(x+4);
    check_increasing(x+y);
    check_increasing(x*4);
    check_increasing(min(x+4, y+4));
    check_increasing(max(x+y, x-y));
    check_increasing(x >= y);
    check_increasing(x > y);

    check_decreasing(-x);
    check_decreasing(x*-4);
    check_decreasing(y - x);
    check_decreasing(x < y);
    check_decreasing(x <= y);

    check_unknown(x == y);
    check_unknown(x != y);
    check_unknown(x*y);

    check_increasing(select(y == 2, x, x+4));
    check_decreasing(select(y == 2, -x, x*-4));

    check_increasing(select(x > 2, x+1, x));
    check_increasing(select(x < 2, x, x+1));
    check_decreasing(select(x > 2, -x-1, -x));
    check_decreasing(select(x < 2, -x, -x-1));

    check_unknown(select(x < 2, x, x-5));
    check_unknown(select(x > 2, x-5, x));

    check_constant(y);

    check_increasing(select(x < 17, y, y+1));
    check_increasing(select(x > 17, y, y-1));
    check_decreasing(select(x < 17, y, y-1));
    check_decreasing(select(x > 17, y, y+1));

    check_constant(select(y > 3, y + 23, y - 65));

    std::cout << "is_monotonic test passed" << std::endl;
}

}
}
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	cursor.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::Cursor class.
 *   pqxx::Cursor represents a database cursor.
 *
 * Copyright (c) 2001-2004, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <cstdlib>

#include "pqxx/cursor"
#include "pqxx/result"
#include "pqxx/transaction"

using namespace PGSTD;

int pqxx::cursor_base::get_unique_cursor_num()
{
  if (!m_context) throw logic_error("libpqxx internal error: "
      "cursor in get_unique_cursor_num() has no transaction");
  return m_context->GetUniqueCursorNum();
}

unsigned char pqxx::cursor_base::s_dummy;

pqxx::icursorstream::icursorstream(pqxx::transaction_base &context,
    const string &query,
    const string &basename,
    size_type stride) :
  cursor_base(&context, basename),
  m_stride(stride)
{
  set_stride(stride);
  declare(query);
}

void pqxx::icursorstream::set_stride(size_type n)
{
  if (n < 1)
    throw invalid_argument("Attempt to set cursor stride to " + to_string(n));
  m_stride = n;
}

void pqxx::icursorstream::declare(const string &query)
{
  m_context->exec("DECLARE \"" + name() + "\" "
      		"NO SCROLL CURSOR FOR " + query + " FOR READ ONLY",
	"[DECLARE "+name()+"]");
}

pqxx::result pqxx::icursorstream::fetch()
{
  result r(m_context->exec("FETCH "+to_string(m_stride)+" IN \""+name()+"\""));
  if (r.empty()) m_done = true;
  return r;
}

pqxx::icursorstream &pqxx::icursorstream::ignore(streamsize n)
{
  m_context->exec("MOVE " + to_string(n) + " IN \"" + name() + "\"");
  return *this;
}

<commit_msg>Fixed incompatibility with pre-7.4 backends<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	cursor.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::Cursor class.
 *   pqxx::Cursor represents a database cursor.
 *
 * Copyright (c) 2001-2004, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <cstdlib>

#include "pqxx/cursor"
#include "pqxx/result"
#include "pqxx/transaction"

using namespace PGSTD;

int pqxx::cursor_base::get_unique_cursor_num()
{
  if (!m_context) throw logic_error("libpqxx internal error: "
      "cursor in get_unique_cursor_num() has no transaction");
  return m_context->GetUniqueCursorNum();
}

unsigned char pqxx::cursor_base::s_dummy;

pqxx::icursorstream::icursorstream(pqxx::transaction_base &context,
    const string &query,
    const string &basename,
    size_type stride) :
  cursor_base(&context, basename),
  m_stride(stride)
{
  set_stride(stride);
  declare(query);
}

void pqxx::icursorstream::set_stride(size_type n)
{
  if (n < 1)
    throw invalid_argument("Attempt to set cursor stride to " + to_string(n));
  m_stride = n;
}

void pqxx::icursorstream::declare(const string &query)
{
  // TODO: Add NO SCROLL if backend supports it (7.4 or better)
  stringstream cq, qn;
  cq << "DECLARE \"" << name() << "\" CURSOR FOR " << query << " FOR READ ONLY";
  qn << "[DECLARE " << name() << ']';
  m_context->exec(cq, qn.str());
}

pqxx::result pqxx::icursorstream::fetch()
{
  result r(m_context->exec("FETCH "+to_string(m_stride)+" IN \""+name()+"\""));
  if (r.empty()) m_done = true;
  return r;
}

pqxx::icursorstream &pqxx::icursorstream::ignore(streamsize n)
{
  m_context->exec("MOVE " + to_string(n) + " IN \"" + name() + "\"");
  return *this;
}

<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	result.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::result class and support classes.
 *   pqxx::result represents the set of result tuples from a database query
 *
 * Copyright (c) 2001-2004, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <cassert>	// DEBUG CODE
#include <stdexcept>

#include "pqxx/except"
#include "pqxx/result"

using namespace PGSTD;

pqxx::result &pqxx::result::operator=(const pqxx::result &Other) throw ()
{
  assert(!m_Result || ((Other.m_Result==m_Result) == (&Other==this)));

  if (&Other != this)
  {
    LoseRef();
    MakeRef(Other);
  }

  assert(m_l->m_r == this);
  assert(m_r->m_l == this);
  assert((m_l!=m_r) || ((m_l->m_l==this) && (m_r->m_r==this)));

  return *this;
}

pqxx::result &pqxx::result::operator=(PGresult *Other) throw ()
{
  if (Other != m_Result)
  {
    LoseRef();
    MakeRef(Other);
  }
  return *this;
}

void pqxx::result::swap(pqxx::result &other) throw ()
{
  const result *const l=m_l, *const r=m_r;
  PGresult *p(m_Result);

  m_l = other.m_l;
  m_r = other.m_r;
  m_Result = other.m_Result;
  other.m_l = l;
  other.m_r = r;
  other.m_Result = p;
}

const pqxx::result::tuple pqxx::result::at(pqxx::result::size_type i) const
  throw (out_of_range)
{
  if ((i < 0) || (i >= size()))
    throw out_of_range("Tuple number out of range");

  return operator[](i);
}

void pqxx::result::CheckStatus(const string &Query) const
{
  const string Err = StatusError();
  if (!Err.empty()) throw sql_error(Err, Query);
}

void pqxx::result::CheckStatus(const char Query[]) const
{
  const string Err = StatusError();
  if (!Err.empty()) throw sql_error(Err, string(Query ? Query : ""));
}

string pqxx::result::StatusError() const
{
  if (!m_Result)
    throw runtime_error("No result");

  string Err;

  switch (PQresultStatus(m_Result))
  {
  case PGRES_EMPTY_QUERY: // The string sent to the backend was empty.
  case PGRES_COMMAND_OK: // Successful completion of a command returning no data
  case PGRES_TUPLES_OK: // The query successfully executed
    break;

  case PGRES_COPY_OUT: // Copy Out (from server) data transfer started
  case PGRES_COPY_IN: // Copy In (to server) data transfer started
    break;

  case PGRES_BAD_RESPONSE: // The server's response was not understood
  case PGRES_NONFATAL_ERROR:
  case PGRES_FATAL_ERROR:
    Err = PQresultErrorMessage(m_Result);
    break;

  default:
    throw logic_error("libpqxx internal error: "
		      "pqxx::result: Unrecognized response code " +
		      to_string(int(PQresultStatus(m_Result))));
  }
  return Err;
}

void pqxx::result::MakeRef(PGresult *Other) throw ()
{
  assert(m_l == this);
  assert(m_r == this);
  assert(!m_Result);

  m_Result = Other;
}

void pqxx::result::MakeRef(const pqxx::result &Other) throw ()
{
  assert(m_l == this);
  assert(m_r == this);
  assert(!m_Result);

  m_l = &Other;
  m_r = Other.m_r;

  assert(m_r->m_l == m_l);
  assert(m_l->m_r == m_r);

  m_l->m_r = m_r->m_l = this;
  m_Result = Other.m_Result;

  assert(m_l->m_r == this);
  assert(m_r->m_l == this);
  assert((m_l!=m_r) || ((m_l->m_l==this) && (m_r->m_r==this)));
}

void pqxx::result::LoseRef() throw ()
{
  assert(m_l->m_r == this);
  assert(m_r->m_l == this);
  assert((m_l!=m_r) || ((m_l->m_l==this) && (m_r->m_r==this)));

  if (m_l == this)
  {
    assert(m_r == this);
    if (m_Result) PQclear(m_Result);
  }
  m_Result = 0;
  m_l->m_r = m_r;
  m_r->m_l = m_l;
  m_l = m_r = this;

  assert(m_l->m_r == this);
  assert(m_r->m_l == this);
  assert((m_l!=m_r) || ((m_l->m_l==this) && (m_r->m_r==this)));
}

pqxx::result::size_type pqxx::result::affected_rows() const
{
  const char *const RowsStr = PQcmdTuples(m_Result);
  return RowsStr[0] ? atoi(RowsStr) : 0;
}

const char *pqxx::result::GetValue(pqxx::result::size_type Row,
		                 pqxx::result::tuple::size_type Col) const
{
  return PQgetvalue(m_Result, Row, Col);
}

bool pqxx::result::GetIsNull(pqxx::result::size_type Row,
		           pqxx::result::tuple::size_type Col) const
{
  return PQgetisnull(m_Result, Row, Col) != 0;
}

pqxx::result::field::size_type
pqxx::result::GetLength(pqxx::result::size_type Row,
                        pqxx::result::tuple::size_type Col) const
{
  return PQgetlength(m_Result, Row, Col);
}

int pqxx::result::errorposition() const throw ()
{
  int pos = -1;
  if (m_Result)
  {
    const char *p = PQresultErrorField(m_Result, PG_DIAG_STATEMENT_POSITION);
    if (p) from_string(p, pos);
  }
  return pos;
}

// tuple

pqxx::result::field pqxx::result::tuple::operator[](const char f[]) const
{
  return field(*this, m_Home->column_number(f));
}

pqxx::result::field pqxx::result::tuple::at(const char f[]) const
{
  const int fnum = m_Home->column_number(f);
  if (fnum == -1)
    throw invalid_argument(string("Unknown field '") + f + "'");

  return field(*this, fnum);
}

pqxx::result::field
pqxx::result::tuple::at(pqxx::result::tuple::size_type i) const throw (out_of_range)
{
  if ((i < 0) || (i >= size()))
    throw out_of_range("Invalid field number");

  return operator[](i);
}

const char *
pqxx::result::column_name(pqxx::result::tuple::size_type Number) const
{
  const char *const N = PQfname(m_Result, Number);
  if (!N)
    throw out_of_range("Invalid column number: " + to_string(Number));

  return N;
}

pqxx::result::tuple::size_type
pqxx::result::column_number(const char ColName[]) const
{
  const tuple::size_type N = PQfnumber(m_Result, ColName);
  if (N == -1)
    throw invalid_argument("Unknown column name: '" + string(ColName) + "'");

  return N;
}

// const_iterator

pqxx::result::const_iterator pqxx::result::const_iterator::operator++(int)
{
  const_iterator Old(*this);
  m_Index++;
  return Old;
}

pqxx::result::const_iterator pqxx::result::const_iterator::operator--(int)
{
  const_iterator Old(*this);
  m_Index--;
  return Old;
}

<commit_msg>Removed debug code<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	result.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::result class and support classes.
 *   pqxx::result represents the set of result tuples from a database query
 *
 * Copyright (c) 2001-2004, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <stdexcept>

#include "pqxx/except"
#include "pqxx/result"

using namespace PGSTD;

pqxx::result &pqxx::result::operator=(const pqxx::result &Other) throw ()
{
  if (&Other != this)
  {
    LoseRef();
    MakeRef(Other);
  }

  return *this;
}

pqxx::result &pqxx::result::operator=(PGresult *Other) throw ()
{
  if (Other != m_Result)
  {
    LoseRef();
    MakeRef(Other);
  }
  return *this;
}

void pqxx::result::swap(pqxx::result &other) throw ()
{
  const result *const l=m_l, *const r=m_r;
  PGresult *p(m_Result);

  m_l = other.m_l;
  m_r = other.m_r;
  m_Result = other.m_Result;
  other.m_l = l;
  other.m_r = r;
  other.m_Result = p;
}

const pqxx::result::tuple pqxx::result::at(pqxx::result::size_type i) const
  throw (out_of_range)
{
  if ((i < 0) || (i >= size()))
    throw out_of_range("Tuple number out of range");

  return operator[](i);
}

void pqxx::result::CheckStatus(const string &Query) const
{
  const string Err = StatusError();
  if (!Err.empty()) throw sql_error(Err, Query);
}

void pqxx::result::CheckStatus(const char Query[]) const
{
  const string Err = StatusError();
  if (!Err.empty()) throw sql_error(Err, string(Query ? Query : ""));
}

string pqxx::result::StatusError() const
{
  if (!m_Result)
    throw runtime_error("No result");

  string Err;

  switch (PQresultStatus(m_Result))
  {
  case PGRES_EMPTY_QUERY: // The string sent to the backend was empty.
  case PGRES_COMMAND_OK: // Successful completion of a command returning no data
  case PGRES_TUPLES_OK: // The query successfully executed
    break;

  case PGRES_COPY_OUT: // Copy Out (from server) data transfer started
  case PGRES_COPY_IN: // Copy In (to server) data transfer started
    break;

  case PGRES_BAD_RESPONSE: // The server's response was not understood
  case PGRES_NONFATAL_ERROR:
  case PGRES_FATAL_ERROR:
    Err = PQresultErrorMessage(m_Result);
    break;

  default:
    throw logic_error("libpqxx internal error: "
		      "pqxx::result: Unrecognized response code " +
		      to_string(int(PQresultStatus(m_Result))));
  }
  return Err;
}

void pqxx::result::MakeRef(PGresult *Other) throw ()
{
  m_Result = Other;
}

void pqxx::result::MakeRef(const pqxx::result &Other) throw ()
{
  m_l = &Other;
  m_r = Other.m_r;

  m_l->m_r = m_r->m_l = this;
  m_Result = Other.m_Result;
}

void pqxx::result::LoseRef() throw ()
{
  if ((m_l == this) && m_Result) PQclear(m_Result);
  m_Result = 0;
  m_l->m_r = m_r;
  m_r->m_l = m_l;
  m_l = m_r = this;
}

pqxx::result::size_type pqxx::result::affected_rows() const
{
  const char *const RowsStr = PQcmdTuples(m_Result);
  return RowsStr[0] ? atoi(RowsStr) : 0;
}

const char *pqxx::result::GetValue(pqxx::result::size_type Row,
		                 pqxx::result::tuple::size_type Col) const
{
  return PQgetvalue(m_Result, Row, Col);
}

bool pqxx::result::GetIsNull(pqxx::result::size_type Row,
		           pqxx::result::tuple::size_type Col) const
{
  return PQgetisnull(m_Result, Row, Col) != 0;
}

pqxx::result::field::size_type
pqxx::result::GetLength(pqxx::result::size_type Row,
                        pqxx::result::tuple::size_type Col) const
{
  return PQgetlength(m_Result, Row, Col);
}

int pqxx::result::errorposition() const throw ()
{
  int pos = -1;
  if (m_Result)
  {
    const char *p = PQresultErrorField(m_Result, PG_DIAG_STATEMENT_POSITION);
    if (p) from_string(p, pos);
  }
  return pos;
}

// tuple

pqxx::result::field pqxx::result::tuple::operator[](const char f[]) const
{
  return field(*this, m_Home->column_number(f));
}

pqxx::result::field pqxx::result::tuple::at(const char f[]) const
{
  const int fnum = m_Home->column_number(f);
  if (fnum == -1)
    throw invalid_argument(string("Unknown field '") + f + "'");

  return field(*this, fnum);
}

pqxx::result::field
pqxx::result::tuple::at(pqxx::result::tuple::size_type i) const throw (out_of_range)
{
  if ((i < 0) || (i >= size()))
    throw out_of_range("Invalid field number");

  return operator[](i);
}

const char *
pqxx::result::column_name(pqxx::result::tuple::size_type Number) const
{
  const char *const N = PQfname(m_Result, Number);
  if (!N)
    throw out_of_range("Invalid column number: " + to_string(Number));

  return N;
}

pqxx::result::tuple::size_type
pqxx::result::column_number(const char ColName[]) const
{
  const tuple::size_type N = PQfnumber(m_Result, ColName);
  if (N == -1)
    throw invalid_argument("Unknown column name: '" + string(ColName) + "'");

  return N;
}

// const_iterator

pqxx::result::const_iterator pqxx::result::const_iterator::operator++(int)
{
  const_iterator Old(*this);
  m_Index++;
  return Old;
}

pqxx::result::const_iterator pqxx::result::const_iterator::operator--(int)
{
  const_iterator Old(*this);
  m_Index--;
  return Old;
}

<|endoftext|>


<commit_before>#include "RapidDecay.h"

#include <iostream>

#include "TMath.h"
#include "TRandom.h"

#include "RapidExternalEvtGen.h"
#include "RapidMomentumSmearGauss.h"
#include "RapidMomentumSmearHisto.h"
#include "RapidParam.h"
#include "RapidParticle.h"
#include "RapidParticleData.h"

void RapidDecay::setParentKinematics(TH1* ptHisto, TH1* etaHisto) {
	std::cout << "INFO in RapidDecay::setParentKinematics : setting kinematics of the parent." << std::endl;
	ptHisto_=ptHisto;
	etaHisto_=etaHisto;
}

void RapidDecay::setAcceptRejectHist(TH1* histo, RapidParam* param) {
	accRejParameterX_ = param;
	accRejParameterY_ = 0;
	accRejHisto_      = histo;

	//correct the histogram to account for the the phasespace distribution
	TH1* denom = generateAccRejDenominator1D();
	accRejHisto_->Divide(denom);
	delete denom;
}

void RapidDecay::setAcceptRejectHist(TH1* histo, RapidParam* paramX, RapidParam* paramY) {
	accRejParameterX_ = paramX;
	accRejParameterY_ = paramY;
	accRejHisto_      = histo;

	//correct the histogram to account for the the phasespace distribution
	TH2* denom = generateAccRejDenominator2D();
	accRejHisto_->Divide(denom);
	delete denom;
}

void RapidDecay::setExternal(RapidExternalGenerator* external) {
	external_ = external;
}

bool RapidDecay::checkDecay() {
	for(unsigned int i=0; i<parts_.size(); ++i) {
		RapidParticle* part = parts_[i];
		if(part->nDaughters()>0) {
			if(!decay_.SetDecay(part->getP(), part->nDaughters(), part->daughterMasses())) {
				std::cout << "ERROR in RapidDecay::checkDecay : decay of " << part->name() << " is kinematically forbidden." << std::endl;
				return false;
			}
		}
	}
	return true;
}

bool RapidDecay::generate() {
	//keep resonance masses and parent kinematics independent of the accept/reject decision
	//these will only be biased if the function is very inefficient for certain values
	//however, one should not use an a/r function the is highly correlated to these variables
	floatMasses();
	genParent();

	bool decayed(false);
	if(external_) {
		decayed = external_->decay(parts_);
	}

	if(!decayed) {
		if(accRejHisto_) {
			if(!genDecayAccRej()) return false;

		} else {
			if(!genDecay()) return false;
		}
	}

	smearMomenta();
    smearIPs();

	return true;
}

void RapidDecay::smearMomenta() {
	//run backwards so that we reach the daughters first
	for(int i=parts_.size()-1; i>=0; --i) {//don't change to unsigned - needs to hit -1 to break loop
		parts_[i]->smearMomentum();
	}

}

void RapidDecay::smearIPs() {
    //run backwards so that we reach the daughters first
    for(int i=parts_.size()-1; i>=0; --i) {//don't change to unsigned - needs to hit -1 to break loop
        parts_[i]->smearIP();
    }
}

void RapidDecay::setup() {
	setupMasses();

	std::cout << "INFO in RapidDecay::setup : Particle summary follows:" << std::endl;
	printf("index\tlabel\t\t   ID\t\tmass (GeV/c^2)\tparent\t\t# children\tchildren\n");
	for(unsigned int i=0; i<parts_.size(); ++i) {
		parts_[i]->print(i);
	}
}

void RapidDecay::floatMasses() {
	for(unsigned int i=0; i<parts_.size(); ++i) {
		parts_[i]->floatMass();
	}
}

void RapidDecay::setupMasses() {
	RapidParticleData* particleData = RapidParticleData::getInstance();

	for(unsigned int i=0; i<parts_.size(); ++i) {
		particleData->setupMass(parts_[i]);
	}
}

bool RapidDecay::runAcceptReject() {
	if(accRejParameterY_) return runAcceptReject2D();
	else return runAcceptReject1D();
}

bool RapidDecay::runAcceptReject1D() {
	double val = accRejParameterX_->eval();
	int bin = accRejHisto_->FindBin(val);

	double score(0.);
	if(!accRejHisto_->IsBinOverflow(bin) && !accRejHisto_->IsBinUnderflow(bin)) {
		score = accRejHisto_->Interpolate(val);
	}
	double max = accRejHisto_->GetMaximum();
	if(score > gRandom->Uniform(max)) return true;
	return false;
}

bool RapidDecay::runAcceptReject2D() {
	double valX = accRejParameterX_->eval();
	double valY = accRejParameterY_->eval();
	int bin = accRejHisto_->FindBin(valX,valY);

	double score(0.);
	if(!accRejHisto_->IsBinOverflow(bin) && !accRejHisto_->IsBinUnderflow(bin)) {
		score = accRejHisto_->Interpolate(valX,valY);
	}
	double max = accRejHisto_->GetMaximum();
	if(score > gRandom->Uniform(max)) return true;
	return false;
}

TH1* RapidDecay::generateAccRejDenominator1D() {
	TH1* denomHisto = dynamic_cast<TH1*>(accRejHisto_->Clone("denom"));
	denomHisto->Reset();

	std::cout << "INFO in RapidDecay::generateAccRejDenominator : generating 1M decays to remove the \"phasespace\" distribution..." << std::endl;
	for(int i=0; i<1000000; ++i) {
		floatMasses();
		genParent();
		if(!genDecay(true)) continue;
		denomHisto->Fill(accRejParameterX_->eval());
	}
	return denomHisto;
}

TH2* RapidDecay::generateAccRejDenominator2D() {
	TH2* denomHisto = dynamic_cast<TH2*>(accRejHisto_->Clone("denom"));
	denomHisto->Reset();

	std::cout << "INFO in RapidDecay::generateAccRejDenominator : generating 1M decays to remove the \"phasespace\" distribution..." << std::endl;
	for(int i=0; i<1000000; ++i) {
		floatMasses();
		genParent();
		if(!genDecay(true)) continue;
		denomHisto->Fill(accRejParameterX_->eval(), accRejParameterY_->eval());
	}
	return denomHisto;
}

void RapidDecay::genParent() {
	double pt(0), eta(0), phi(gRandom->Uniform(0,2*TMath::Pi()));
	if(ptHisto_)   pt = ptHisto_->GetRandom();
	if(etaHisto_) eta = etaHisto_->GetRandom();
	parts_[0]->setPtEtaPhi(pt,eta,phi);
}

bool RapidDecay::genDecay(bool acceptAny) {
    //The origin vertex of the signal is always 0,0,0
    ROOT::Math::XYZPoint signalpv(0.,0.,0.);
	for(unsigned int i=0; i<parts_.size(); ++i) {
		RapidParticle* part = parts_[i];
		if(part->nDaughters()>0) {
			// check decay kinematics valid
			if(!decay_.SetDecay(part->getP(), part->nDaughters(), part->daughterMasses())) {
				if(!suppressKinematicWarning_) {
					std::cout << "WARNING in RapidDecay::genDecay : decay of " << part->name() << " is kinematically forbidden for some events due to resonance mass shapes." << std::endl
						  << "                                  these events will not be generated." << std::endl
						  << "                                  further warnings will be suppressed." << std::endl;
					suppressKinematicWarning_ = true;
				}
				return false;
			}

			// make an event
			if(acceptAny) {
				decay_.Generate();
			} else {
				int nGen(0);
				bool accept(false);
				while (nGen < maxgen_ && accept == false){
					accept = decay_.Generate() > gRandom->Uniform();
					++nGen;
				} // while

				if(!accept) {
					if(!suppressAttemptsWarning_) {
						std::cout << "WARNING in RapidDecay::genDecay : rejected all " << maxgen_ << " attempts to decay " << part->name() << "." << std::endl
							  << "                                  this event will not be generated." << std::endl
							  << "                                  further warnings will be suppressed." << std::endl;
					suppressAttemptsWarning_ = true;
					}
					return false;
				}
			}
            // Now generate the decay vertex for long-lived particles
            // First set the origin vertex to be the PV for the head of the chain
            // in all other cases, the origin vertex will already be set in the loop below
            if (!part->mother()) part->setOriginVertex(signalpv);
            double dist = part->mass()*gRandom->Exp(part->ctau())/part->getP().P();
            double dvx  = part->getOriginVertex().X() + part->getP().Vect().Unit().X()*dist;
            double dvy  = part->getOriginVertex().Y() + part->getP().Vect().Unit().Y()*dist;
            double dvz  = part->getOriginVertex().Z() + part->getP().Vect().Unit().Z()*dist;
            part->setDecayVertex(ROOT::Math::XYZPoint(dvx,dvy,dvz));

			int j=0;
            ROOT::Math::XYZPoint decayvertex(0.,0.,0.);
			for(RapidParticle* jDaug=part->daughter(0); jDaug!=0; jDaug=jDaug->next()) {
				jDaug->setP(*decay_.GetDecay(j++));
                jDaug->setOriginVertex(part->getDecayVertex());
                double ip(0.);
                ip = getParticleIP(signalpv,jDaug->getOriginVertex(),jDaug->getP());
                jDaug->setIP(ip);
			}
		}
	}

	return true;
}

double RapidDecay::getParticleIP(ROOT::Math::XYZPoint pv, ROOT::Math::XYZPoint dv, TLorentzVector p) {
  ROOT::Math::XYZVector v1 = pv - dv;
  ROOT::Math::XYZVector dispv(dv.X() + p.X(), dv.Y()+p.Y(), dv.Z()+p.Z());
  ROOT::Math::XYZVector lengthv(p.X(), p.Y(), p.Z());
  ROOT::Math::XYZVector v2 = pv - (dv + dispv);

  ROOT::Math::XYZVector impact = v1.Cross(v2)/sqrt(lengthv.Mag2());

  return sqrt(impact.Mag2());
}

bool RapidDecay::genDecayAccRej() {
	bool passAccRej(true);
	int ntry(0);

	do {
		if(!genDecay(true)) return false;
		passAccRej = runAcceptReject();
		++ntry;

	} while(!passAccRej && ntry<maxgen_);

	if(!passAccRej) {
		if(!suppressAttemptsWarning_) {
			std::cout << "WARNING in RapidDecay::genDecayAccRej : no events found with required kinematics." << std::endl
				  << "                                        this event will not be generated." << std::endl
				  << "                                        further warnings will be suppressed." << std::endl;
			suppressAttemptsWarning_ = true;
		}
		return false;
	}

	return true;
}
<commit_msg>fix second trivial bug<commit_after>#include "RapidDecay.h"

#include <iostream>

#include "TMath.h"
#include "TRandom.h"

#include "RapidExternalEvtGen.h"
#include "RapidMomentumSmearGauss.h"
#include "RapidMomentumSmearHisto.h"
#include "RapidParam.h"
#include "RapidParticle.h"
#include "RapidParticleData.h"

void RapidDecay::setParentKinematics(TH1* ptHisto, TH1* etaHisto) {
	std::cout << "INFO in RapidDecay::setParentKinematics : setting kinematics of the parent." << std::endl;
	ptHisto_=ptHisto;
	etaHisto_=etaHisto;
}

void RapidDecay::setAcceptRejectHist(TH1* histo, RapidParam* param) {
	accRejParameterX_ = param;
	accRejParameterY_ = 0;
	accRejHisto_      = histo;

	//correct the histogram to account for the the phasespace distribution
	TH1* denom = generateAccRejDenominator1D();
	accRejHisto_->Divide(denom);
	delete denom;
}

void RapidDecay::setAcceptRejectHist(TH1* histo, RapidParam* paramX, RapidParam* paramY) {
	accRejParameterX_ = paramX;
	accRejParameterY_ = paramY;
	accRejHisto_      = histo;

	//correct the histogram to account for the the phasespace distribution
	TH2* denom = generateAccRejDenominator2D();
	accRejHisto_->Divide(denom);
	delete denom;
}

void RapidDecay::setExternal(RapidExternalGenerator* external) {
	external_ = external;
}

bool RapidDecay::checkDecay() {
	for(unsigned int i=0; i<parts_.size(); ++i) {
		RapidParticle* part = parts_[i];
		if(part->nDaughters()>0) {
			if(!decay_.SetDecay(part->getP(), part->nDaughters(), part->daughterMasses())) {
				std::cout << "ERROR in RapidDecay::checkDecay : decay of " << part->name() << " is kinematically forbidden." << std::endl;
				return false;
			}
		}
	}
	return true;
}

bool RapidDecay::generate() {
	//keep resonance masses and parent kinematics independent of the accept/reject decision
	//these will only be biased if the function is very inefficient for certain values
	//however, one should not use an a/r function the is highly correlated to these variables
	floatMasses();
	genParent();

	bool decayed(false);
	if(external_) {
		decayed = external_->decay(parts_);
	}

	if(!decayed) {
		if(accRejHisto_) {
			if(!genDecayAccRej()) return false;

		} else {
			if(!genDecay()) return false;
		}
	}

	smearMomenta();
    smearIPs();

	return true;
}

void RapidDecay::smearMomenta() {
	//run backwards so that we reach the daughters first
	for(int i=parts_.size()-1; i>=0; --i) {//don't change to unsigned - needs to hit -1 to break loop
		parts_[i]->smearMomentum();
	}

}

void RapidDecay::smearIPs() {
    //run backwards so that we reach the daughters first
    for(int i=parts_.size()-1; i>=0; --i) {//don't change to unsigned - needs to hit -1 to break loop
        parts_[i]->smearIP();
    }
}

void RapidDecay::setup() {
	setupMasses();

	std::cout << "INFO in RapidDecay::setup : Particle summary follows:" << std::endl;
	printf("index\tlabel\t\t   ID\t\tmass (GeV/c^2)\tparent\t\t# children\tchildren\n");
	for(unsigned int i=0; i<parts_.size(); ++i) {
		parts_[i]->print(i);
	}
}

void RapidDecay::floatMasses() {
	for(unsigned int i=0; i<parts_.size(); ++i) {
		parts_[i]->floatMass();
	}
}

void RapidDecay::setupMasses() {
	RapidParticleData* particleData = RapidParticleData::getInstance();

	for(unsigned int i=0; i<parts_.size(); ++i) {
		particleData->setupMass(parts_[i]);
	}
}

bool RapidDecay::runAcceptReject() {
	if(accRejParameterY_) return runAcceptReject2D();
	else return runAcceptReject1D();
}

bool RapidDecay::runAcceptReject1D() {
	double val = accRejParameterX_->eval();
	int bin = accRejHisto_->FindBin(val);

	double score(0.);
	if(!accRejHisto_->IsBinOverflow(bin) && !accRejHisto_->IsBinUnderflow(bin)) {
		score = accRejHisto_->Interpolate(val);
	}
	double max = accRejHisto_->GetMaximum();
	if(score > gRandom->Uniform(max)) return true;
	return false;
}

bool RapidDecay::runAcceptReject2D() {
	double valX = accRejParameterX_->eval();
	double valY = accRejParameterY_->eval();
	int bin = accRejHisto_->FindBin(valX,valY);

	double score(0.);
	if(!accRejHisto_->IsBinOverflow(bin) && !accRejHisto_->IsBinUnderflow(bin)) {
		score = accRejHisto_->Interpolate(valX,valY);
	}
	double max = accRejHisto_->GetMaximum();
	if(score > gRandom->Uniform(max)) return true;
	return false;
}

TH1* RapidDecay::generateAccRejDenominator1D() {
	TH1* denomHisto = dynamic_cast<TH1*>(accRejHisto_->Clone("denom"));
	denomHisto->Reset();

	std::cout << "INFO in RapidDecay::generateAccRejDenominator : generating 1M decays to remove the \"phasespace\" distribution..." << std::endl;
	for(int i=0; i<1000000; ++i) {
		floatMasses();
		genParent();
		if(!genDecay(true)) continue;
		denomHisto->Fill(accRejParameterX_->eval());
	}
	return denomHisto;
}

TH2* RapidDecay::generateAccRejDenominator2D() {
	TH2* denomHisto = dynamic_cast<TH2*>(accRejHisto_->Clone("denom"));
	denomHisto->Reset();

	std::cout << "INFO in RapidDecay::generateAccRejDenominator : generating 1M decays to remove the \"phasespace\" distribution..." << std::endl;
	for(int i=0; i<1000000; ++i) {
		floatMasses();
		genParent();
		if(!genDecay(true)) continue;
		denomHisto->Fill(accRejParameterX_->eval(), accRejParameterY_->eval());
	}
	return denomHisto;
}

void RapidDecay::genParent() {
	double pt(0), eta(0), phi(gRandom->Uniform(0,2*TMath::Pi()));
	if(ptHisto_)   pt = ptHisto_->GetRandom();
	if(etaHisto_) eta = etaHisto_->GetRandom();
	parts_[0]->setPtEtaPhi(pt,eta,phi);
}

bool RapidDecay::genDecay(bool acceptAny) {
    //The origin vertex of the signal is always 0,0,0
    ROOT::Math::XYZPoint signalpv(0.,0.,0.);
	for(unsigned int i=0; i<parts_.size(); ++i) {
		RapidParticle* part = parts_[i];
		if(part->nDaughters()>0) {
			// check decay kinematics valid
			if(!decay_.SetDecay(part->getP(), part->nDaughters(), part->daughterMasses())) {
				if(!suppressKinematicWarning_) {
					std::cout << "WARNING in RapidDecay::genDecay : decay of " << part->name() << " is kinematically forbidden for some events due to resonance mass shapes." << std::endl
						  << "                                  these events will not be generated." << std::endl
						  << "                                  further warnings will be suppressed." << std::endl;
					suppressKinematicWarning_ = true;
				}
				return false;
			}

			// make an event
			if(acceptAny) {
				decay_.Generate();
			} else {
				int nGen(0);
				bool accept(false);
				while (nGen < maxgen_ && accept == false){
					accept = decay_.Generate() > gRandom->Uniform();
					++nGen;
				} // while

				if(!accept) {
					if(!suppressAttemptsWarning_) {
						std::cout << "WARNING in RapidDecay::genDecay : rejected all " << maxgen_ << " attempts to decay " << part->name() << "." << std::endl
							  << "                                  this event will not be generated." << std::endl
							  << "                                  further warnings will be suppressed." << std::endl;
					suppressAttemptsWarning_ = true;
					}
					return false;
				}
			}
            // Now generate the decay vertex for long-lived particles
            // First set the origin vertex to be the PV for the head of the chain
            // in all other cases, the origin vertex will already be set in the loop below
            if (!part->mother()) part->setOriginVertex(signalpv);
            double dist = part->getP().P()*gRandom->Exp(part->ctau())/part->mass();
            double dvx  = part->getOriginVertex().X() + part->getP().Vect().Unit().X()*dist;
            double dvy  = part->getOriginVertex().Y() + part->getP().Vect().Unit().Y()*dist;
            double dvz  = part->getOriginVertex().Z() + part->getP().Vect().Unit().Z()*dist;
            part->setDecayVertex(ROOT::Math::XYZPoint(dvx,dvy,dvz));

			int j=0;
            ROOT::Math::XYZPoint decayvertex(0.,0.,0.);
			for(RapidParticle* jDaug=part->daughter(0); jDaug!=0; jDaug=jDaug->next()) {
				jDaug->setP(*decay_.GetDecay(j++));
                jDaug->setOriginVertex(part->getDecayVertex());
                double ip(0.);
                ip = getParticleIP(signalpv,jDaug->getOriginVertex(),jDaug->getP());
                jDaug->setIP(ip);
			}
		}
	}

	return true;
}

double RapidDecay::getParticleIP(ROOT::Math::XYZPoint pv, ROOT::Math::XYZPoint dv, TLorentzVector p) {
  ROOT::Math::XYZVector v1 = pv - dv;
  ROOT::Math::XYZVector dispv(dv.X() + p.X(), dv.Y()+p.Y(), dv.Z()+p.Z());
  ROOT::Math::XYZVector lengthv(p.X(), p.Y(), p.Z());
  ROOT::Math::XYZVector v2 = pv - (dv + dispv);

  ROOT::Math::XYZVector impact = v1.Cross(v2)/sqrt(lengthv.Mag2());

  return sqrt(impact.Mag2());
}

bool RapidDecay::genDecayAccRej() {
	bool passAccRej(true);
	int ntry(0);

	do {
		if(!genDecay(true)) return false;
		passAccRej = runAcceptReject();
		++ntry;

	} while(!passAccRej && ntry<maxgen_);

	if(!passAccRej) {
		if(!suppressAttemptsWarning_) {
			std::cout << "WARNING in RapidDecay::genDecayAccRej : no events found with required kinematics." << std::endl
				  << "                                        this event will not be generated." << std::endl
				  << "                                        further warnings will be suppressed." << std::endl;
			suppressAttemptsWarning_ = true;
		}
		return false;
	}

	return true;
}
<|endoftext|>


<commit_before>/*
 * RelayNode.cpp
 * Homie Node for a Relay with optional status indicator LED
 *
 * Version: 1.1
 * Author: Lübbe Onken (http://github.com/luebbe)
 */

#include "RelayNode.hpp"

RelayNode::RelayNode(const char *name, const int relayPin, const int ledPin, const bool reverseSignal)
    : HomieNode(name, "RelayNode", "actor")
{
  _relayPin = relayPin;
  _ledPin = ledPin;
  if (reverseSignal)
  {
    _relayOnValue = LOW;
    _relayOffValue = HIGH;
  }
  else
  {
    _relayOnValue = HIGH;
    _relayOffValue = LOW;
  }
  advertise("on")
      .setDatatype("boolean")
      .settable();

  advertise("timeout")
      .setDatatype("integer")
      .settable();
}

HomieInternals::Uptime relayUptime;

bool RelayNode::handleOnOff(const String &value)
{
  if (value == "true" || value == "false" || value == "toggle")
  {
    if (value == "toggle")
    {
      bool current = getRelay();
      setRelay(!current);
    }
    else
      setRelay(value == "true");
    return true;
  }
  else
  {
    return false;
  }
}

#define IS_INTEGER(s) (s == String(s.toInt()))

bool RelayNode::handleTimeout(const String &value)
{
  if (IS_INTEGER(value))
  {
    long timeout = value.toInt();
    if (timeout > 0)
    {
      setRelay(true, timeout);
      return true;
    }
  }
  return false;
}

bool RelayNode::handleInput(const HomieRange &range, const String &property, const String &value)
{
  Homie.getLogger() << "Message: " << property << " " << value << endl;

  if (property.equals("on"))
  {
    return handleOnOff(value);
  }
  else if (property.equals("timeout"))
  {
    return handleTimeout(value);
  }
  else
  {
    return false;
  }
}

void RelayNode::onReadyToOperate()
{
  setRelay(false);
  sendState();
};

void RelayNode::printCaption()
{
  Homie.getLogger() << cCaption << endl;
}

void RelayNode::sendState()
{
  printCaption();
  bool on = getRelay();
  Homie.getLogger() << cIndent << "Relay is " << (on ? "on" : "off") << endl;
  if (Homie.isConnected())
  {
    setProperty("on").send(on ? "true" : "false");
    setProperty("timeout").send(String(long(_timeout)));
  }
}

void RelayNode::setLed(bool on)
{
  if (_ledPin > DEFAULTPIN)
  {
    digitalWrite(_ledPin, on ? LOW : HIGH); // LOW = LED on
  }
}

bool RelayNode::getRelay()
{
  if (_relayPin > DEFAULTPIN)
  {
    return digitalRead(_relayPin) == _relayOnValue;
  }
  else
  {
    return false;
  }
}

void RelayNode::setRelay(bool on, long timeoutSecs)
{
  if (_relayPin > DEFAULTPIN)
  {
    digitalWrite(_relayPin, on ? _relayOnValue : _relayOffValue);
    if (on && timeoutSecs > 0)
    {
      _timeout = relayUptime.getSeconds() + timeoutSecs;
    }
    else
    {
      _timeout = 0;
    }
    sendState();
  }
  else
  {
    Homie.getLogger() << cIndent << "No Relay Pin!" << endl;
  }
  // Set Led according to relay
  setLed(on);
}

void RelayNode::toggleRelay()
{
  setRelay(!getRelay());
}

void RelayNode::setup()
{
  printCaption();

  Homie.getLogger() << cIndent << "Relay Pin: " << _relayPin << endl
                    << cIndent << "Led Pin  : " << _ledPin << endl;

  if (_ledPin > DEFAULTPIN)
  {
    pinMode(_ledPin, OUTPUT);
  }

  if (_relayPin > DEFAULTPIN)
  {
    pinMode(_relayPin, OUTPUT);
  }
}

void RelayNode::loop()
{
  relayUptime.update();
  if ((_timeout > 0) && getRelay() && (_timeout < relayUptime.getSeconds()))
  {
    setRelay(false);
  }
}
<commit_msg>Fix RelayNode: sendState only necessary after setRelay Relay has to be set to false in Setup()<commit_after>/*
 * RelayNode.cpp
 * Homie Node for a Relay with optional status indicator LED
 *
 * Version: 1.1
 * Author: Lübbe Onken (http://github.com/luebbe)
 */

#include "RelayNode.hpp"

RelayNode::RelayNode(const char *name, const int relayPin, const int ledPin, const bool reverseSignal)
    : HomieNode(name, "RelayNode", "actor")
{
  _relayPin = relayPin;
  _ledPin = ledPin;
  if (reverseSignal)
  {
    _relayOnValue = LOW;
    _relayOffValue = HIGH;
  }
  else
  {
    _relayOnValue = HIGH;
    _relayOffValue = LOW;
  }
  advertise("on")
      .setDatatype("boolean")
      .settable();

  advertise("timeout")
      .setDatatype("integer")
      .settable();
}

HomieInternals::Uptime relayUptime;

bool RelayNode::handleOnOff(const String &value)
{
  if (value == "true" || value == "false" || value == "toggle")
  {
    if (value == "toggle")
    {
      bool current = getRelay();
      setRelay(!current);
    }
    else
      setRelay(value == "true");
    return true;
  }
  else
  {
    return false;
  }
}

#define IS_INTEGER(s) (s == String(s.toInt()))

bool RelayNode::handleTimeout(const String &value)
{
  if (IS_INTEGER(value))
  {
    long timeout = value.toInt();
    if (timeout > 0)
    {
      setRelay(true, timeout);
      return true;
    }
  }
  return false;
}

bool RelayNode::handleInput(const HomieRange &range, const String &property, const String &value)
{
  Homie.getLogger() << "Message: " << property << " " << value << endl;

  if (property.equals("on"))
  {
    return handleOnOff(value);
  }
  else if (property.equals("timeout"))
  {
    return handleTimeout(value);
  }
  else
  {
    return false;
  }
}

void RelayNode::onReadyToOperate()
{
  setRelay(false);
};

void RelayNode::printCaption()
{
  Homie.getLogger() << cCaption << endl;
}

void RelayNode::sendState()
{
  printCaption();
  bool on = getRelay();
  Homie.getLogger() << cIndent << "Relay is " << (on ? "on" : "off") << endl;
  if (Homie.isConnected())
  {
    setProperty("on").send(on ? "true" : "false");
    setProperty("timeout").send(String(long(_timeout)));
  }
}

void RelayNode::setLed(bool on)
{
  if (_ledPin > DEFAULTPIN)
  {
    digitalWrite(_ledPin, on ? LOW : HIGH); // LOW = LED on
  }
}

bool RelayNode::getRelay()
{
  if (_relayPin > DEFAULTPIN)
  {
    return digitalRead(_relayPin) == _relayOnValue;
  }
  else
  {
    return false;
  }
}

void RelayNode::setRelay(bool on, long timeoutSecs)
{
  if (_relayPin > DEFAULTPIN)
  {
    digitalWrite(_relayPin, on ? _relayOnValue : _relayOffValue);
    if (on && timeoutSecs > 0)
    {
      _timeout = relayUptime.getSeconds() + timeoutSecs;
    }
    else
    {
      _timeout = 0;
    }
    sendState();
  }
  else
  {
    Homie.getLogger() << cIndent << "No Relay Pin!" << endl;
  }
  // Set Led according to relay
  setLed(on);
}

void RelayNode::toggleRelay()
{
  setRelay(!getRelay());
}

void RelayNode::setup()
{
  printCaption();

  Homie.getLogger() << cIndent << "Relay Pin: " << _relayPin << endl
                    << cIndent << "Led Pin  : " << _ledPin << endl;

  if (_ledPin > DEFAULTPIN)
  {
    pinMode(_ledPin, OUTPUT);
  }
  if (_relayPin > DEFAULTPIN)
  {
    pinMode(_relayPin, OUTPUT);
  }
  setRelay(false);
}

void RelayNode::loop()
{
  relayUptime.update();
  if ((_timeout > 0) && getRelay() && (_timeout < relayUptime.getSeconds()))
  {
    setRelay(false);
  }
}
<|endoftext|>


<commit_before>#include "cssysdef.h"
#include "csutil/mmapio.h"

csMemoryMappedIO::csMemoryMappedIO(unsigned _block_size, char *filename):
  block_size(_block_size)
{
  valid_mmio_object = MemoryMapFile(&platform, filename);
}

csMemoryMappedIO::~csMemoryMappedIO()
{
  UnMemoryMapFile(&platform);
}

void *
csMemoryMappedIO::GetPointer(unsigned int index)
{

#ifdef CS_HAS_MEMORY_MAPPED_IO

  return platform.data + (index*block_size);

#else

  unsigned int page = index/cache_block_size;

  if (!(*page_map)[page])
    CachePage(page);

  // This MUST come AFTER CachPage b/c CachePage might re-orient things.
  CacheBlock *cp = cache[page % csmmioDefaultHashSize];

  while(cp)
  {
    if (cp->page==page)
    {
      // Decrease age
      ++cp->age;

      return cp->data + ((index-cp->offset)*block_size);
    }

    cp=cp->next;
  }

  //Serious error! The page is marked as here, but we could not find it!
  return NULL;

#endif

}

/////////////////////////////////////////// Software Support for Memory Mapping ///////////////////////////////////

#ifndef CS_HAS_MEMORY_MAPPED_IO

bool
csMemoryMappedIO::MemoryMapFile(mmioInfo *_platform, char *filename)
{
  if ((_platform->hMappedFile=fopen(filename, "rb")) != NULL)
  {
    return false;
  }
  else
  {
    // Create a page map with one bit per cache block.
    page_map = new csBitArray(_platform->file_size/cache_block_size);

    // Clear the cache
    memset(&cache, 0, sizeof(cache));

    // Set that we're good to go.
    return true;
  }
}

void
csMemoryMappedIO::UnMemoryMapFile(mmioInfo *_platform)
{
  if (_platform->hMappedFile)
    fclose(_platform->hMappedFile);

  if (page_map)
    delete page_map;

  unsigned int i;
  CacheBlock *cp, *np;

  // Free all allocated memory.
  for(i=0; i<csmmioDefaultHashSize; ++i)
  {
    cp=cache[i];
    while(cp)
    {
     np=cp->next;
     delete [] cp->data;
     delete cp;

     cp=np;
    }
  }
}

void
csMemoryMappedIO::CachePage(unsigned int page)
{
  unsigned int bucket = page % csmmioDefaultHashSize;

  CacheBlock *cp;

  if (cache_block_count < cache_max_size)
  {
    cp = new CacheBlock;
    ++cache_block_count;

    // Insert it into the bucket.
    cp->next=cache[bucket];
    cache[bucket]=cp;

    // Initialize it
    cp->data = new unsigned char[block_size * cache_block_size];
  }
  else
  {
    CacheBlock *block;

    // Find the least used block in this bucket.
    cp=cache[bucket];
    block=cp->next;

    while(block)
    {
      if (block->age < cp->age)
        cp=block;

      block=block->next;
    }

    // Unmark this page as allocated
    page_map->ClearBit(cp->page);
  }

  // Get the data for it.
  cp->offset=page*cache_block_size;
  cp->page=page;
  cp->age=0;

  // Mark this page as allocated
  page_map->SetBit(page);

  // Read the page from the file
  fseek(mapped_file, page*cache_block_size*block_size, SEEK_SET);
  fread(cp->data, block_size, cache_block_size, mapped_file);
}

#endif<commit_msg>1. Bugfixes:<commit_after>#include "cssysdef.h"
#include "csutil/mmapio.h"

csMemoryMappedIO::csMemoryMappedIO(unsigned _block_size, char *filename):
  block_size(_block_size)
{
  valid_mmio_object = MemoryMapFile(&platform, filename);
}

csMemoryMappedIO::~csMemoryMappedIO()
{
  UnMemoryMapFile(&platform);
}

/////////////////////////////////////////// Software Support for Memory Mapping ///////////////////////////////////

#ifndef CS_HAS_MEMORY_MAPPED_IO

bool
csMemoryMappedIO::MemoryMapFile(mmioInfo *_platform, char *filename)
{
  // Clear the page map
  page_map = NULL;

  // Clear the cache
  memset(&cache, 0, sizeof(cache));

  // Initialize cache management variables
  cache_block_size = csmmioDefaultCacheBlockSize;
  cache_max_size = csmmioDefaultCacheSize;
  cache_block_count=0;

  if ((_platform->hMappedFile=fopen(filename, "rb")) == NULL)
  {
    return false;
  }
  else
  {
    // Create a page map with one bit per cache block.
    page_map = new csBitArray(_platform->file_size/cache_block_size);

    // Clear all of it's bits
    page_map->Clear();

    // Set that we're good to go.
    return true;
  }
}

void
csMemoryMappedIO::UnMemoryMapFile(mmioInfo *_platform)
{
  if (_platform->hMappedFile)
    fclose(_platform->hMappedFile);

  if (page_map)
    delete page_map;

  unsigned int i;
  CacheBlock *cp, *np;

  // Free all allocated memory.
  for(i=0; i<csmmioDefaultHashSize; ++i)
  {
    cp=cache[i];
    while(cp)
    {
     np=cp->next;
     delete [] cp->data;
     delete cp;

     cp=np;
    }
  }
}

void
csMemoryMappedIO::CachePage(unsigned int page)
{
  unsigned int bucket = page % csmmioDefaultHashSize;

  CacheBlock *cp;

  if (cache_block_count < cache_max_size)
  {
    cp = new CacheBlock;
    ++cache_block_count;

    // Insert it into the bucket.
    cp->next=cache[bucket];
    cache[bucket]=cp;

    // Initialize it
    cp->data = new unsigned char[block_size * cache_block_size];
  }
  else
  {
    CacheBlock *block;

    // Find the least used block in this bucket.
    cp=cache[bucket];
    block=cp->next;

    while(block)
    {
      if (block->age < cp->age)
        cp=block;

      block=block->next;
    }

    // Unmark this page as allocated
    page_map->ClearBit(cp->page);
  }

  // Get the data for it.
  cp->offset=page*cache_block_size;
  cp->page=page;
  cp->age=0;

  // Mark this page as allocated
  page_map->SetBit(page);

  // Read the page from the file
  fseek(platform.hMappedFile, page*cache_block_size*block_size, SEEK_SET);
  fread(cp->data, block_size, cache_block_size, platform.hMappedFile);
}

#endif<|endoftext|>


<commit_before>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "SliceAllocation.hxx"
#include "util/Compiler.h"

#include <boost/intrusive/list.hpp>

#include <stddef.h>

struct AllocatorStats;
class SliceArea;

/**
 * The "slice" memory allocator.  It is an allocator for large numbers
 * of small fixed-size objects.
 */
class SlicePool {
	friend class SliceArea;

	size_t slice_size;

	/**
	 * Number of slices that fit on one MMU page (4 kB).
	 */
	unsigned slices_per_page;

	unsigned pages_per_slice;

	unsigned pages_per_area;

	unsigned slices_per_area;

	/**
	 * Number of pages for the area header.
	 */
	unsigned header_pages;

	size_t area_size;

	typedef boost::intrusive::list<SliceArea,
				       boost::intrusive::base_hook<boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>>,
				       boost::intrusive::constant_time_size<false>> AreaList;

	AreaList areas;

	/**
	 * A list of #SliceArea instances which are empty.  They are kept
	 * in a separate list to reduce fragmentation: allocate first from
	 * areas which are not empty.
	 */
	AreaList empty_areas;

	/**
	 * A list of #SliceArea instances which are full.  They are kept
	 * in a separate list to speed up allocation, to avoid iterating
	 * over full areas.
	 */
	AreaList full_areas;

	bool fork_cow = true;

public:
	SlicePool(size_t _slice_size, unsigned _slices_per_area) noexcept;
	~SlicePool() noexcept;

	size_t GetSliceSize() const noexcept {
		return slice_size;
	}

	/**
	 * Controls whether forked child processes inherit the allocator.
	 * This is enabled by default.
	 */
	void ForkCow(bool inherit) noexcept;

	void AddStats(AllocatorStats &stats, const AreaList &list) const noexcept;

	gcc_pure
	AllocatorStats GetStats() const noexcept;

	void Compress() noexcept;

	gcc_pure
	SliceArea *FindNonFullArea() noexcept;

	SliceArea &MakeNonFullArea() noexcept;

	SliceAllocation Alloc() noexcept;
	void Free(SliceArea &area, void *p) noexcept;
};
<commit_msg>SlicePool: make two methods private<commit_after>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "SliceAllocation.hxx"
#include "util/Compiler.h"

#include <boost/intrusive/list.hpp>

#include <stddef.h>

struct AllocatorStats;
class SliceArea;

/**
 * The "slice" memory allocator.  It is an allocator for large numbers
 * of small fixed-size objects.
 */
class SlicePool {
	friend class SliceArea;

	size_t slice_size;

	/**
	 * Number of slices that fit on one MMU page (4 kB).
	 */
	unsigned slices_per_page;

	unsigned pages_per_slice;

	unsigned pages_per_area;

	unsigned slices_per_area;

	/**
	 * Number of pages for the area header.
	 */
	unsigned header_pages;

	size_t area_size;

	typedef boost::intrusive::list<SliceArea,
				       boost::intrusive::base_hook<boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>>,
				       boost::intrusive::constant_time_size<false>> AreaList;

	AreaList areas;

	/**
	 * A list of #SliceArea instances which are empty.  They are kept
	 * in a separate list to reduce fragmentation: allocate first from
	 * areas which are not empty.
	 */
	AreaList empty_areas;

	/**
	 * A list of #SliceArea instances which are full.  They are kept
	 * in a separate list to speed up allocation, to avoid iterating
	 * over full areas.
	 */
	AreaList full_areas;

	bool fork_cow = true;

public:
	SlicePool(size_t _slice_size, unsigned _slices_per_area) noexcept;
	~SlicePool() noexcept;

	size_t GetSliceSize() const noexcept {
		return slice_size;
	}

	/**
	 * Controls whether forked child processes inherit the allocator.
	 * This is enabled by default.
	 */
	void ForkCow(bool inherit) noexcept;

	void AddStats(AllocatorStats &stats, const AreaList &list) const noexcept;

	gcc_pure
	AllocatorStats GetStats() const noexcept;

	void Compress() noexcept;

	SliceAllocation Alloc() noexcept;
	void Free(SliceArea &area, void *p) noexcept;

private:
	gcc_pure
	SliceArea *FindNonFullArea() noexcept;

	SliceArea &MakeNonFullArea() noexcept;
};
<|endoftext|>