<commit_before>#include "tests-base.hpp"

#include "utf8rewind.h"

#include "helpers-strings.hpp"

TEST(WideToUtf8, BasicLatin)
{
	wchar_t i[] = { 'c', 'o', 'n', 'n', 'e', 'c', 't' };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(7, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("connect", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, BasicLatinAmountOfBytes)
{
	wchar_t i[] = { '$', ' ', '4', '.', '3', '3' };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, BasicLatinNotEnoughSpace)
{
	wchar_t i[] = { 'r', 'o', 'c', 'k', 'e', 't' };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 4;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("rock", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(WideToUtf8, TwoBytes)
{
	// MODIFIER LETTER LOW VERTICAL LINE
	// ARABIC LETTER NOON GHUNNA
	// GREEK CAPITAL LETTER BETA

	wchar_t i[] = { 0x02CC, 0x06BA, 0x0392 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xCB\x8C\xDA\xBA\xCE\x92", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, TwoBytesAmountOfBytes)
{
	// 03F7;GREEK CAPITAL LETTER SHO
	// 0572;ARMENIAN SMALL LETTER GHAD
	// 03CF;GREEK CAPITAL KAI SYMBOL

	wchar_t i[] = { 0x03F7, 0x0572, 0x03CF };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, TwoBytesNotEnoughSpace)
{
	// HEBREW POINT HATAF SEGOL
	// NKO LETTER A
	// ARABIC LETTER YEH WITH THREE DOTS BELOW

	wchar_t i[] = { 0x05B1, 0x07CA, 0x06D1 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 5;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xD6\xB1\xDF\x8A", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(WideToUtf8, ThreeBytes)
{
	// DEVANAGARI LETTER JA
	// DEVANAGARI LETTER DDA
	// DEVANAGARI LETTER TA

	wchar_t i[] = { 0x091C, 0x0921, 0x0924 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(9, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xE0\xA4\x9C\xE0\xA4\xA1\xE0\xA4\xA4", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, ThreeBytesAmountOfBytes)
{
	// ETHIOPIC SYLLABLE BU
	// VEDIC SIGN TIRYAK
	// NEW TAI LUE LETTER LOW KVA
	// ORIYA LETTER BHA

	wchar_t i[] = { 0x1261, 0x1CED, 0x19A8, 0x0B2D };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(12, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, ThreeBytesNotEnoughSpace)
{
	// MONGOLIAN LETTER MANCHU ALI GALI GHA
	// CANADIAN SYLLABICS MI
	// CANADIAN SYLLABICS TYO

	wchar_t i[] = { 0x189A, 0x14A5, 0x1572 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 7;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xE1\xA2\x9A\xE1\x92\xA5", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

#if UTF8_WCHAR_UTF32

TEST(WideToUtf8, FourBytes)
{
	// UNAMUSED FACE
	// HEAVY NORTH WEST POINTING VINE LEAF
	// ALCHEMICAL SYMBOL FOR DISTILL

	wchar_t i[] = { 0x1F612, 0x1F760, 0x1F65C };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(12, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xF0\x9F\x98\x92\xF0\x9F\x9D\xA0\xF0\x9F\x99\x9C", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, FourBytesAmountOfBytes)
{
	// TRAIN
	// RINGING BELL
	// FRAME WITH TILES
	// DOCUMENT WITH PICTURE

	wchar_t i[] = { 0x1F686, 0x1F56D, 0x1F5BD, 0x1F5BB };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(16, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, FourBytesNotEnoughSpace)
{
	// BABY SYMBOL
	// CJK COMPATIBILITY IDEOGRAPH-2F93A

	wchar_t i[] = { 0x1F6BC, 0x2F93A };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 5;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xF0\x9F\x9A\xBC", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

#endif

TEST(WideToUtf8, SurrogatePair)
{
	const wchar_t i[] = { 0xD834, 0xDD1E, 0xDA88, 0xDC10 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xF0\x9D\x84\x9E\xF2\xB2\x80\x90", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, SurrogatePairAmountOfBytes)
{
	const wchar_t i[] = { 0xDAAD, 0xDC12, 0xDB01, 0xDC45 };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, SurrogatePairNotEnoughSpace)
{
	const wchar_t i[] = { 0xDBFE, 0xDFFE, 0xD818, 0xDCDE };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 3;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(WideToUtf8, InvalidData)
{
	int32_t errors = 0;

	EXPECT_EQ(0, widetoutf8(nullptr, sizeof(wchar_t), nullptr, 1, &errors));
	EXPECT_ERROREQ(UTF8_ERR_INVALID_DATA, errors);
}<commit_msg>suite-wide-toutf8: Added tests for overlapping parameters.<commit_after>#include "tests-base.hpp"

#include "utf8rewind.h"

#include "helpers-strings.hpp"

TEST(WideToUtf8, BasicLatin)
{
	wchar_t i[] = { 'c', 'o', 'n', 'n', 'e', 'c', 't' };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(7, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("connect", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, BasicLatinAmountOfBytes)
{
	wchar_t i[] = { '$', ' ', '4', '.', '3', '3' };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, BasicLatinNotEnoughSpace)
{
	wchar_t i[] = { 'r', 'o', 'c', 'k', 'e', 't' };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 4;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("rock", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(WideToUtf8, TwoBytes)
{
	// MODIFIER LETTER LOW VERTICAL LINE
	// ARABIC LETTER NOON GHUNNA
	// GREEK CAPITAL LETTER BETA

	wchar_t i[] = { 0x02CC, 0x06BA, 0x0392 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xCB\x8C\xDA\xBA\xCE\x92", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, TwoBytesAmountOfBytes)
{
	// 03F7;GREEK CAPITAL LETTER SHO
	// 0572;ARMENIAN SMALL LETTER GHAD
	// 03CF;GREEK CAPITAL KAI SYMBOL

	wchar_t i[] = { 0x03F7, 0x0572, 0x03CF };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, TwoBytesNotEnoughSpace)
{
	// HEBREW POINT HATAF SEGOL
	// NKO LETTER A
	// ARABIC LETTER YEH WITH THREE DOTS BELOW

	wchar_t i[] = { 0x05B1, 0x07CA, 0x06D1 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 5;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xD6\xB1\xDF\x8A", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(WideToUtf8, ThreeBytes)
{
	// DEVANAGARI LETTER JA
	// DEVANAGARI LETTER DDA
	// DEVANAGARI LETTER TA

	wchar_t i[] = { 0x091C, 0x0921, 0x0924 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(9, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xE0\xA4\x9C\xE0\xA4\xA1\xE0\xA4\xA4", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, ThreeBytesAmountOfBytes)
{
	// ETHIOPIC SYLLABLE BU
	// VEDIC SIGN TIRYAK
	// NEW TAI LUE LETTER LOW KVA
	// ORIYA LETTER BHA

	wchar_t i[] = { 0x1261, 0x1CED, 0x19A8, 0x0B2D };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(12, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, ThreeBytesNotEnoughSpace)
{
	// MONGOLIAN LETTER MANCHU ALI GALI GHA
	// CANADIAN SYLLABICS MI
	// CANADIAN SYLLABICS TYO

	wchar_t i[] = { 0x189A, 0x14A5, 0x1572 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 7;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xE1\xA2\x9A\xE1\x92\xA5", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

#if UTF8_WCHAR_UTF32

TEST(WideToUtf8, FourBytes)
{
	// UNAMUSED FACE
	// HEAVY NORTH WEST POINTING VINE LEAF
	// ALCHEMICAL SYMBOL FOR DISTILL

	wchar_t i[] = { 0x1F612, 0x1F760, 0x1F65C };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(12, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xF0\x9F\x98\x92\xF0\x9F\x9D\xA0\xF0\x9F\x99\x9C", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, FourBytesAmountOfBytes)
{
	// TRAIN
	// RINGING BELL
	// FRAME WITH TILES
	// DOCUMENT WITH PICTURE

	wchar_t i[] = { 0x1F686, 0x1F56D, 0x1F5BD, 0x1F5BB };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(16, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, FourBytesNotEnoughSpace)
{
	// BABY SYMBOL
	// CJK COMPATIBILITY IDEOGRAPH-2F93A

	wchar_t i[] = { 0x1F6BC, 0x2F93A };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 5;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xF0\x9F\x9A\xBC", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

#endif

TEST(WideToUtf8, SurrogatePair)
{
	const wchar_t i[] = { 0xD834, 0xDD1E, 0xDA88, 0xDC10 };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xF0\x9D\x84\x9E\xF2\xB2\x80\x90", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, SurrogatePairAmountOfBytes)
{
	const wchar_t i[] = { 0xDAAD, 0xDC12, 0xDB01, 0xDC45 };
	size_t is = sizeof(i);
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, widetoutf8(i, is, nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, SurrogatePairNotEnoughSpace)
{
	const wchar_t i[] = { 0xDBFE, 0xDFFE, 0xD818, 0xDCDE };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 3;
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("", o);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(WideToUtf8, ErrorsIsReset)
{
	const wchar_t i[] = { 0x0A9A };
	size_t is = sizeof(i);
	char o[256] = { 0 };
	size_t os = 255;
	int32_t errors = 776;

	EXPECT_EQ(3, widetoutf8(i, is, o, os, &errors));
	EXPECT_UTF8EQ("\xE0\xAA\x9A", o);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, InvalidData)
{
	int32_t errors = 0;

	EXPECT_EQ(0, widetoutf8(nullptr, sizeof(wchar_t), nullptr, 1, &errors));
	EXPECT_ERROREQ(UTF8_ERR_INVALID_DATA, errors);
}

TEST(WideToUtf8, OverlappingParametersFits)
{
	int32_t errors = 0;

	uint8_t data[128] = { 0 };
	data[0 * sizeof(wchar_t)] = 'o';
	data[1 * sizeof(wchar_t)] = 'f';
	data[2 * sizeof(wchar_t)] = 'f';
	data[3 * sizeof(wchar_t)] = 's';
	data[4 * sizeof(wchar_t)] = 'e';
	data[5 * sizeof(wchar_t)] = 't';

	const wchar_t* i = (const wchar_t*)data;
	size_t is = 6 * sizeof(wchar_t);
	char* o = (char*)(data + is);
	size_t os = 6;

	EXPECT_EQ(6, widetoutf8(i, is, o, os, &errors));
#if UTF8_WCHAR_UTF32
	EXPECT_MEMEQ("o\0\0\0f\0\0\0f\0\0\0s\0\0\0e\0\0\0t\0\0\0offset", (const char*)data, 30);
#else
	EXPECT_MEMEQ("o\0f\0f\0s\0e\0t\0offset", (const char*)data, 18);
#endif
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST(WideToUtf8, OverlappingParametersStartsEqual)
{
	int32_t errors = 0;

	uint8_t data[128] = { 0 };

	const wchar_t* i = (const wchar_t*)data;
	size_t is = 13 * sizeof(wchar_t);
	char* o = (char*)data;
	size_t os = 4 * sizeof(wchar_t);

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_ERROREQ(UTF8_ERR_OVERLAPPING_PARAMETERS, errors);
}

TEST(WideToUtf8, OverlappingParametersEndsEqual)
{
	int32_t errors = 0;

	uint8_t data[128] = { 0 };

	const wchar_t* i = (const wchar_t*)data;
	size_t is = 12 * sizeof(wchar_t);
	char* o = (char*)(data + (4 * sizeof(wchar_t)));
	size_t os = 8 * sizeof(wchar_t);

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_ERROREQ(UTF8_ERR_OVERLAPPING_PARAMETERS, errors);
}

TEST(WideToUtf8, OverlappingParametersInputStartsInTarget)
{
	int32_t errors = 0;

	uint8_t data[128] = { 0 };

	const wchar_t* i = (const wchar_t*)(data + (17 * sizeof(wchar_t)));
	size_t is = 12 * sizeof(wchar_t);
	char* o = (char*)(data + (8 * sizeof(wchar_t)));
	size_t os = 27 * sizeof(wchar_t);

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_ERROREQ(UTF8_ERR_OVERLAPPING_PARAMETERS, errors);
}

TEST(WideToUtf8, OverlappingParametersInputEndsInTarget)
{
	int32_t errors = 0;

	uint8_t data[128] = { 0 };

	const wchar_t* i = (const wchar_t*)(data + (3 * sizeof(wchar_t)));
	size_t is = 27 * sizeof(wchar_t);
	char* o = (char*)(data + (24 * sizeof(wchar_t)));
	size_t os = 16 * sizeof(wchar_t);

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_ERROREQ(UTF8_ERR_OVERLAPPING_PARAMETERS, errors);
}

TEST(WideToUtf8, OverlappingParametersInputInsideTarget)
{
	int32_t errors = 0;

	uint8_t data[128] = { 0 };

	const wchar_t* i = (const wchar_t*)(data + (12 * sizeof(wchar_t)));
	size_t is = 6 * sizeof(wchar_t);
	char* o = (char*)(data + (10 * sizeof(wchar_t)));
	size_t os = 10 * sizeof(wchar_t);

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_ERROREQ(UTF8_ERR_OVERLAPPING_PARAMETERS, errors);
}

TEST(WideToUtf8, OverlappingParametersTargetStartsInInput)
{
	int32_t errors = 0;

	uint8_t data[128] = { 0 };

	const wchar_t* i = (const wchar_t*)(data + (15 * sizeof(wchar_t)));
	size_t is = 11 * sizeof(wchar_t);
	char* o = (char*)(data + (18 * sizeof(wchar_t)));
	size_t os = 23 * sizeof(wchar_t);

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_ERROREQ(UTF8_ERR_OVERLAPPING_PARAMETERS, errors);
}

TEST(WideToUtf8, OverlappingParametersTargetEndsInInput)
{
	int32_t errors = 0;

	uint8_t data[128] = { 0 };

	const wchar_t* i = (const wchar_t*)(data + (5 * sizeof(wchar_t)));
	size_t is = 18 * sizeof(wchar_t);
	char* o = (char*)(data + (2 * sizeof(wchar_t)));
	size_t os = 9 * sizeof(wchar_t);

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_ERROREQ(UTF8_ERR_OVERLAPPING_PARAMETERS, errors);
}

TEST(WideToUtf8, OverlappingParametersTargetInsideInput)
{
	int32_t errors = 0;

	uint8_t data[128] = { 0 };

	const wchar_t* i = (const wchar_t*)(data + (14 * sizeof(wchar_t)));
	size_t is = 21 * sizeof(wchar_t);
	char* o = (char*)(data + (17 * sizeof(wchar_t)));
	size_t os = 7 * sizeof(wchar_t);

	EXPECT_EQ(0, widetoutf8(i, is, o, os, &errors));
	EXPECT_ERROREQ(UTF8_ERR_OVERLAPPING_PARAMETERS, errors);
}<|endoftext|>


<commit_before>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

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

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

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "geographical_coord.h"
#include <iomanip>

namespace navitia { namespace type {

double GeographicalCoord::distance_to(const GeographicalCoord &other) const{
    double longitudeArc = (this->lon() - other.lon()) * N_DEG_TO_RAD;
    double latitudeArc  = (this->lat() - other.lat()) * N_DEG_TO_RAD;
    double latitudeH = sin(latitudeArc * 0.5);
    latitudeH *= latitudeH;
    double lontitudeH = sin(longitudeArc * 0.5);
    lontitudeH *= lontitudeH;
    double tmp = cos(this->lat()*N_DEG_TO_RAD) * cos(other.lat()*N_DEG_TO_RAD);
    return EARTH_RADIUS_IN_METERS * 2.0 * asin(sqrt(latitudeH + tmp*lontitudeH));
}

bool operator==(const GeographicalCoord & a, const GeographicalCoord & b){
    return a.distance_to(b) < 0.1; // soit 0.1m
}

std::pair<GeographicalCoord, float> GeographicalCoord::project(GeographicalCoord segment_start, GeographicalCoord segment_end) const{
    std::pair<GeographicalCoord, float> result;

    double dlon = segment_end._lon - segment_start._lon;
    double dlat = segment_end._lat - segment_start._lat;
    double length_sqr = dlon * dlon + dlat * dlat;
    double u;

    // On gère le cas où le segment est particulièrement court, et donc ça peut poser des problèmes (à cause de la division par length²)
    if(length_sqr < 1e-11){ // moins de un mètre, on projette sur une extrémité
        if(this->distance_to(segment_start) < this->distance_to(segment_end))
            u = 0;
        else
            u = 1;
    } else {
        u = ((this->_lon - segment_start._lon)*dlon + (this->_lat - segment_start._lat)*dlat )/
                length_sqr;
    }

    // Les deux cas où le projeté tombe en dehors
    if(u < 0)
        result = std::make_pair(segment_start, this->distance_to(segment_start));
    else if(u > 1)
        result = std::make_pair(segment_end, this->distance_to(segment_end));
    else {
        result.first._lon = segment_start._lon + u * (segment_end._lon - segment_start._lon);
        result.first._lat = segment_start._lat + u * (segment_end._lat - segment_start._lat);
        result.second = this->distance_to(result.first);
    }

    return result;
}

std::ostream & operator<<(std::ostream & os, const GeographicalCoord & coord){
    os << coord.lon() << ";" << coord.lat();
    return os;
}

GeographicalCoord project(const LineString& line, const GeographicalCoord& p) {
    if (line.empty()) { return p; }

    // project the p on the way
    GeographicalCoord projected = line.front();
    float min_dist = p.distance_to(projected);
    GeographicalCoord prev = line.front();
    auto cur = line.begin();
    for (++cur; cur != line.end(); prev = *cur, ++cur) {
        auto projection = p.project(prev, *cur);
        if (projection.second < min_dist) {
            min_dist = projection.second;
            projected = projection.first;
        }
    }

    return projected;
}

GeographicalCoord project(const MultiLineString& multiline, const GeographicalCoord& p) {
    if (multiline.empty()) { return p; }

    GeographicalCoord projected;
    float min_dist = std::numeric_limits<float>::infinity();
    for (const auto& line: multiline) {
        const auto projection = project(line, p);
        const auto cur_dist = projection.distance_to(p);
        if (cur_dist < min_dist) {
            min_dist = cur_dist;
            projected = projection;
        }
    }

    return projected;
}

}}// namespace navitia::type

navitia::type::GeographicalCoord in_the_right_interval(double lon, double lat) {
    if (fabs(lat) > 90) {
        lat = fmod(lat, 360);
        if (fabs(lat) > 90) {
            if (fabs(lat) > 270) {
                lat = (std::signbit(lat) ? 1 : -1) * (90 - fabs(fmod(lat, 90)));
            } else {
                lon = - lon;
                if (fabs(lat) > 180) {
                    lat = (std::signbit(lat) ? 1 : -1) * fabs(fmod(lat, 90));
                } else {
                    lat = (std::signbit(lat) ? - 1 : 1) * (90 - fabs(fmod(lat, 90)));
                }
            }
        }
    }
    if (fabs(lon > 180)) {
        lon = fmod(lon, 360);
        if (fabs(lon) > 180) {
            lon = (std::signbit(lon) ? 1 : -1) * (180 - fabs(fmod(lon, 180)));
        }
    }
    return navitia::type::GeographicalCoord(lon, lat);
}

namespace boost { namespace geometry { namespace model {
inline std::ostream& operator<<(std::ostream& os, const navitia::type::Polygon& points){
    os << "{\"type\":\"Polygon\",\"coordinates\":[[";
    os << std::setprecision(16) << "[" << points.outer()[0].lon() << ", " << points.outer()[0].lat() << "]";
    for(size_t i = 1; i <= points.outer().size() - 1; i++) {
        os << std::setprecision(16) << ",[" << points.outer()[i].lon() << ", " << points.outer()[i].lat() << "]";
    }
    return os << "]]}";
}

inline std::ostream& operator<<(std::ostream& os, const navitia::type::MultiPolygon& polygons){
    os << "{\"type\":\"MultiPolygon\",\"coordinates\":[";
    for (int unsigned i = 0; i < polygons.size() - 1; i++) {
        os << std::setprecision(16) << "[[["<< polygons[i].outer()[0].lon();
        os << std::setprecision(16) << "," << polygons[i].outer()[0].lat() << "]";
        //for (int j = 0)
        for(int unsigned j =1; j < polygons[i].outer().size(); j++){
            os << std::setprecision(16) << ",[" <<polygons[i].outer()[j].lon();
            os << std::setprecision(16) << "," << polygons[i].outer()[j].lat() << "]";
        }
        os << "]]";
        if ( i == (polygons.size() - 1) ) continue;
        os << ",";
    }
    return os << "]}";
}
}}}//namespace boost::geometry::model
<commit_msg>correction<commit_after>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

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

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

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "geographical_coord.h"
#include <iomanip>

namespace navitia { namespace type {

double GeographicalCoord::distance_to(const GeographicalCoord &other) const{
    double longitudeArc = (this->lon() - other.lon()) * N_DEG_TO_RAD;
    double latitudeArc  = (this->lat() - other.lat()) * N_DEG_TO_RAD;
    double latitudeH = sin(latitudeArc * 0.5);
    latitudeH *= latitudeH;
    double lontitudeH = sin(longitudeArc * 0.5);
    lontitudeH *= lontitudeH;
    double tmp = cos(this->lat()*N_DEG_TO_RAD) * cos(other.lat()*N_DEG_TO_RAD);
    return EARTH_RADIUS_IN_METERS * 2.0 * asin(sqrt(latitudeH + tmp*lontitudeH));
}

bool operator==(const GeographicalCoord & a, const GeographicalCoord & b){
    return a.distance_to(b) < 0.1; // soit 0.1m
}

std::pair<GeographicalCoord, float> GeographicalCoord::project(GeographicalCoord segment_start, GeographicalCoord segment_end) const{
    std::pair<GeographicalCoord, float> result;

    double dlon = segment_end._lon - segment_start._lon;
    double dlat = segment_end._lat - segment_start._lat;
    double length_sqr = dlon * dlon + dlat * dlat;
    double u;

    // On gère le cas où le segment est particulièrement court, et donc ça peut poser des problèmes (à cause de la division par length²)
    if(length_sqr < 1e-11){ // moins de un mètre, on projette sur une extrémité
        if(this->distance_to(segment_start) < this->distance_to(segment_end))
            u = 0;
        else
            u = 1;
    } else {
        u = ((this->_lon - segment_start._lon)*dlon + (this->_lat - segment_start._lat)*dlat )/
                length_sqr;
    }

    // Les deux cas où le projeté tombe en dehors
    if(u < 0)
        result = std::make_pair(segment_start, this->distance_to(segment_start));
    else if(u > 1)
        result = std::make_pair(segment_end, this->distance_to(segment_end));
    else {
        result.first._lon = segment_start._lon + u * (segment_end._lon - segment_start._lon);
        result.first._lat = segment_start._lat + u * (segment_end._lat - segment_start._lat);
        result.second = this->distance_to(result.first);
    }

    return result;
}

std::ostream & operator<<(std::ostream & os, const GeographicalCoord & coord){
    os << coord.lon() << ";" << coord.lat();
    return os;
}

GeographicalCoord project(const LineString& line, const GeographicalCoord& p) {
    if (line.empty()) { return p; }

    // project the p on the way
    GeographicalCoord projected = line.front();
    float min_dist = p.distance_to(projected);
    GeographicalCoord prev = line.front();
    auto cur = line.begin();
    for (++cur; cur != line.end(); prev = *cur, ++cur) {
        auto projection = p.project(prev, *cur);
        if (projection.second < min_dist) {
            min_dist = projection.second;
            projected = projection.first;
        }
    }

    return projected;
}

GeographicalCoord project(const MultiLineString& multiline, const GeographicalCoord& p) {
    if (multiline.empty()) { return p; }

    GeographicalCoord projected;
    float min_dist = std::numeric_limits<float>::infinity();
    for (const auto& line: multiline) {
        const auto projection = project(line, p);
        const auto cur_dist = projection.distance_to(p);
        if (cur_dist < min_dist) {
            min_dist = cur_dist;
            projected = projection;
        }
    }

    return projected;
}

}}// namespace navitia::type

navitia::type::GeographicalCoord in_the_right_interval(double lon, double lat) {
    if (fabs(lat) > 90) {
        lat = fmod(lat, 360);
        if (fabs(lat) > 90) {
            if (fabs(lat) > 270) {
                lat = (std::signbit(lat) ? 1 : -1) * (90 - fabs(fmod(lat, 90)));
            } else {
                lon = - lon;
                if (fabs(lat) > 180) {
                    lat = (std::signbit(lat) ? 1 : -1) * fabs(fmod(lat, 90));
                } else {
                    lat = (std::signbit(lat) ? - 1 : 1) * (90 - fabs(fmod(lat, 90)));
                }
            }
        }
    }
    if (fabs(lon > 180)) {
        lon = fmod(lon, 360);
        if (fabs(lon) > 180) {
            lon = (std::signbit(lon) ? 1 : -1) * (180 - fabs(fmod(lon, 180)));
        }
    }
    return navitia::type::GeographicalCoord(lon, lat);
}

namespace boost { namespace geometry { namespace model {
inline std::ostream& operator<<(std::ostream& os, const navitia::type::Polygon& points){
    os << "{\"type\":\"Polygon\",\"coordinates\":[[";
    os << std::setprecision(16) << "[" << points.outer()[0].lon() << ", " << points.outer()[0].lat() << "]";
    for(const auto coord: points.outer()) {
        os << std::setprecision(16) << ",[" << coord.lon() << ", " << coord.lat() << "]";
    }
    return os << "]]}";
}

inline std::ostream& operator<<(std::ostream& os, const navitia::type::MultiPolygon& polygons){
    os << "{\"type\":\"MultiPolygon\",\"coordinates\":[";
    for (const auto& polygon: polygons) {
        os << std::setprecision(16) << "[[["<< polygon.outer()[0].lon();
        os << std::setprecision(16) << "," << polygon.outer()[0].lat() << "]";
        for(const auto coord: polygon.outer()){
            os << std::setprecision(16) << ",[" << coord.lon();
            os << std::setprecision(16) << "," << coord.lat() << "]";
        }
        os << "]]";
        if ( i == (polygons.size() - 1) ) continue;
        os << ",";
    }
    return os << "]}";
}
}}}//namespace boost::geometry::model
<|endoftext|>


<commit_before>#pragma once

#include <limits>
#include <cassert>

#include "acmacs-base/vector.hh"
#include "acmacs-base/transformation.hh"
#include "acmacs-base/stream.hh"

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

namespace acmacs
{
    class Coordinates : public Vector
    {
     public:
        using Vector::Vector;

        Coordinates transform(const Transformation& aTransformation) const
            {
                const auto [x, y] = aTransformation.transform(operator[](0), operator[](1));
                return {x, y};
            }

        bool not_nan() const
            {
                return !empty() && std::all_of(begin(), end(), [](double value) -> bool { return ! std::isnan(value); });
            }

    }; // class Coordinates

    inline std::ostream& operator<<(std::ostream& s, const Coordinates& c)
    {
        stream_internal::write_to_stream(s, c, "[", "]", ", ");
        return s;
    }

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

    class LayoutInterface
    {
     public:
        LayoutInterface() = default;
        LayoutInterface(const LayoutInterface&) = default;
        virtual ~LayoutInterface() = default;
        LayoutInterface& operator=(const LayoutInterface&) = default;

        virtual size_t number_of_points() const noexcept = 0;
        virtual size_t number_of_dimensions() const noexcept = 0;
        virtual const Coordinates operator[](size_t aPointNo) const = 0;
        const Coordinates get(size_t aPointNo) const { return operator[](aPointNo); }
        Coordinates& operator[](size_t) = delete; // use set()!
        virtual double coordinate(size_t aPointNo, size_t aDimensionNo) const = 0;
        double operator()(size_t aPointNo, size_t aDimensionNo) const { return coordinate(aPointNo, aDimensionNo); }
        virtual bool point_has_coordinates(size_t point_no) const = 0;
        virtual std::vector<double> as_flat_vector_double() const = 0;
        virtual std::vector<float> as_flat_vector_float() const = 0;

        double distance(size_t p1, size_t p2, double no_distance = std::numeric_limits<double>::quiet_NaN()) const
        {
            const auto c1 = operator[](p1);
            const auto c2 = operator[](p2);
            return (c1.not_nan() && c2.not_nan()) ? c1.distance(c2) : no_distance;
        }

          // returns indexes for min points for each dimension and max points for each dimension
        virtual std::pair<std::vector<size_t>, std::vector<size_t>> min_max_point_indexes() const;
          // returns boundary coordinates (min and max)
        virtual std::pair<Coordinates, Coordinates> boundaries() const;
        virtual LayoutInterface* transform(const Transformation& aTransformation) const;
        virtual Coordinates centroid() const;

        virtual void set(size_t aPointNo, const Coordinates& aCoordinates) = 0;
        virtual void set(size_t point_no, size_t dimension_no, double value) = 0;

    }; // class LayoutInterface

    inline std::ostream& operator<<(std::ostream& s, const LayoutInterface& aLayout)
    {
        s << "Layout [";
        for (size_t no = 0; no < aLayout.number_of_points(); ++no)
            s << aLayout[no] << ' ';
        s << ']';
        return s;
    }

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

    class Layout : public virtual LayoutInterface, public std::vector<double>
    {
     public:
        Layout() = default;
        Layout(size_t aNumberOfPoints, size_t aNumberOfDimensions)
            : std::vector<double>(aNumberOfPoints * aNumberOfDimensions, std::numeric_limits<double>::quiet_NaN()),
            number_of_dimensions_{aNumberOfDimensions}
            {}
        Layout(const Layout&) = default;
        Layout(const LayoutInterface& aSource) : std::vector<double>(aSource.as_flat_vector_double()), number_of_dimensions_{aSource.number_of_dimensions()} {}
        Layout(const LayoutInterface& aSource, const std::vector<size_t>& aIndexes); // make layout by subsetting source
        Layout& operator=(const Layout&) = default;

        size_t number_of_points() const noexcept override { return size() / number_of_dimensions_; }
        size_t number_of_dimensions() const noexcept override { return number_of_dimensions_; }

        void change_number_of_dimensions(size_t num_dim, bool allow_dimensions_increase = false)
            {
                if (!allow_dimensions_increase && num_dim >= number_of_dimensions_) {
                    throw std::runtime_error("Layout::change_number_of_dimensions: dimensions increase: " + std::to_string(number_of_dimensions_) + " --> " + std::to_string(num_dim));
                      // std::cerr << "WARNING: Layout::change_number_of_dimensions: " << number_of_dimensions_ << " --> " << num_dim << '\n';
                }
                resize(number_of_points() * num_dim);
                number_of_dimensions_ = num_dim;
            }

        const Coordinates operator[](size_t aPointNo) const override
            {
                using diff_t = decltype(begin())::difference_type;
                return {begin() + static_cast<diff_t>(aPointNo * number_of_dimensions_), begin() + static_cast<diff_t>((aPointNo + 1) * number_of_dimensions_)};
            }

        double coordinate(size_t aPointNo, size_t aDimensionNo) const override { return at(aPointNo * number_of_dimensions_ + aDimensionNo); }
        bool point_has_coordinates(size_t point_no) const override { return !std::isnan(coordinate(point_no, 0)); }
        std::vector<double> as_flat_vector_double() const override { return *this; }
        std::vector<float> as_flat_vector_float() const override { return {begin(), end()}; }
        void set(size_t aPointNo, const Coordinates& aCoordinates) override
            {
                std::copy(aCoordinates.begin(), aCoordinates.end(), begin() + static_cast<decltype(begin())::difference_type>(aPointNo * number_of_dimensions()));
            }

        void set_nan(size_t aPointNo)
            {
                using diff_t = decltype(begin())::difference_type;
                const auto first{begin() + static_cast<diff_t>(aPointNo * number_of_dimensions())}, last{first + static_cast<diff_t>(number_of_dimensions())};
                std::for_each(first, last, [](auto& target) { target = std::numeric_limits<std::decay_t<decltype(target)>>::quiet_NaN(); });
            }

        virtual void set(size_t point_no, size_t dimension_no, double value) override { std::vector<double>::operator[](point_no * number_of_dimensions() + dimension_no) = value; }

     private:
        size_t number_of_dimensions_;

    }; // class Layout

} // namespace acmacs

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>Coordinates to Location conversion<commit_after>#pragma once

#include <limits>
#include <cassert>

#include "acmacs-base/vector.hh"
#include "acmacs-base/transformation.hh"
#include "acmacs-base/size.hh"
#include "acmacs-base/stream.hh"

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

namespace acmacs
{
    class Coordinates : public Vector
    {
     public:
        using Vector::Vector;

        Coordinates transform(const Transformation& aTransformation) const
            {
                const auto [x, y] = aTransformation.transform(operator[](0), operator[](1));
                return {x, y};
            }

        bool not_nan() const
            {
                return !empty() && std::all_of(begin(), end(), [](double value) -> bool { return ! std::isnan(value); });
            }

        operator Location() const { assert(size() == 2); return {operator[](0), operator[](1)}; }

    }; // class Coordinates

    inline std::ostream& operator<<(std::ostream& s, const Coordinates& c)
    {
        stream_internal::write_to_stream(s, c, "[", "]", ", ");
        return s;
    }

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

    class LayoutInterface
    {
     public:
        LayoutInterface() = default;
        LayoutInterface(const LayoutInterface&) = default;
        virtual ~LayoutInterface() = default;
        LayoutInterface& operator=(const LayoutInterface&) = default;

        virtual size_t number_of_points() const noexcept = 0;
        virtual size_t number_of_dimensions() const noexcept = 0;
        virtual const Coordinates operator[](size_t aPointNo) const = 0;
        const Coordinates get(size_t aPointNo) const { return operator[](aPointNo); }
        Coordinates& operator[](size_t) = delete; // use set()!
        virtual double coordinate(size_t aPointNo, size_t aDimensionNo) const = 0;
        double operator()(size_t aPointNo, size_t aDimensionNo) const { return coordinate(aPointNo, aDimensionNo); }
        virtual bool point_has_coordinates(size_t point_no) const = 0;
        virtual std::vector<double> as_flat_vector_double() const = 0;
        virtual std::vector<float> as_flat_vector_float() const = 0;

        double distance(size_t p1, size_t p2, double no_distance = std::numeric_limits<double>::quiet_NaN()) const
        {
            const auto c1 = operator[](p1);
            const auto c2 = operator[](p2);
            return (c1.not_nan() && c2.not_nan()) ? c1.distance(c2) : no_distance;
        }

          // returns indexes for min points for each dimension and max points for each dimension
        virtual std::pair<std::vector<size_t>, std::vector<size_t>> min_max_point_indexes() const;
          // returns boundary coordinates (min and max)
        virtual std::pair<Coordinates, Coordinates> boundaries() const;
        virtual LayoutInterface* transform(const Transformation& aTransformation) const;
        virtual Coordinates centroid() const;

        virtual void set(size_t aPointNo, const Coordinates& aCoordinates) = 0;
        virtual void set(size_t point_no, size_t dimension_no, double value) = 0;

    }; // class LayoutInterface

    inline std::ostream& operator<<(std::ostream& s, const LayoutInterface& aLayout)
    {
        s << "Layout [";
        for (size_t no = 0; no < aLayout.number_of_points(); ++no)
            s << aLayout[no] << ' ';
        s << ']';
        return s;
    }

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

    class Layout : public virtual LayoutInterface, public std::vector<double>
    {
     public:
        Layout() = default;
        Layout(size_t aNumberOfPoints, size_t aNumberOfDimensions)
            : std::vector<double>(aNumberOfPoints * aNumberOfDimensions, std::numeric_limits<double>::quiet_NaN()),
            number_of_dimensions_{aNumberOfDimensions}
            {}
        Layout(const Layout&) = default;
        Layout(const LayoutInterface& aSource) : std::vector<double>(aSource.as_flat_vector_double()), number_of_dimensions_{aSource.number_of_dimensions()} {}
        Layout(const LayoutInterface& aSource, const std::vector<size_t>& aIndexes); // make layout by subsetting source
        Layout& operator=(const Layout&) = default;

        size_t number_of_points() const noexcept override { return size() / number_of_dimensions_; }
        size_t number_of_dimensions() const noexcept override { return number_of_dimensions_; }

        void change_number_of_dimensions(size_t num_dim, bool allow_dimensions_increase = false)
            {
                if (!allow_dimensions_increase && num_dim >= number_of_dimensions_) {
                    throw std::runtime_error("Layout::change_number_of_dimensions: dimensions increase: " + std::to_string(number_of_dimensions_) + " --> " + std::to_string(num_dim));
                      // std::cerr << "WARNING: Layout::change_number_of_dimensions: " << number_of_dimensions_ << " --> " << num_dim << '\n';
                }
                resize(number_of_points() * num_dim);
                number_of_dimensions_ = num_dim;
            }

        const Coordinates operator[](size_t aPointNo) const override
            {
                using diff_t = decltype(begin())::difference_type;
                return {begin() + static_cast<diff_t>(aPointNo * number_of_dimensions_), begin() + static_cast<diff_t>((aPointNo + 1) * number_of_dimensions_)};
            }

        double coordinate(size_t aPointNo, size_t aDimensionNo) const override { return at(aPointNo * number_of_dimensions_ + aDimensionNo); }
        bool point_has_coordinates(size_t point_no) const override { return !std::isnan(coordinate(point_no, 0)); }
        std::vector<double> as_flat_vector_double() const override { return *this; }
        std::vector<float> as_flat_vector_float() const override { return {begin(), end()}; }
        void set(size_t aPointNo, const Coordinates& aCoordinates) override
            {
                std::copy(aCoordinates.begin(), aCoordinates.end(), begin() + static_cast<decltype(begin())::difference_type>(aPointNo * number_of_dimensions()));
            }

        void set_nan(size_t aPointNo)
            {
                using diff_t = decltype(begin())::difference_type;
                const auto first{begin() + static_cast<diff_t>(aPointNo * number_of_dimensions())}, last{first + static_cast<diff_t>(number_of_dimensions())};
                std::for_each(first, last, [](auto& target) { target = std::numeric_limits<std::decay_t<decltype(target)>>::quiet_NaN(); });
            }

        virtual void set(size_t point_no, size_t dimension_no, double value) override { std::vector<double>::operator[](point_no * number_of_dimensions() + dimension_no) = value; }

     private:
        size_t number_of_dimensions_;

    }; // class Layout

} // namespace acmacs

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


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

#pragma once

#if __has_include(<fmt/format.h>)
  #define N_LOGGER_USE_FMT 1
  #define N_LOGGER_CRIPPLED 0
  #include <fmt/format.h>
#elif __has_include(<format>)
  #define N_LOGGER_USE_FMT 0
  #define N_LOGGER_CRIPPLED 0
  #include <format>
#else
  #define N_LOGGER_USE_FMT 0
  #define N_LOGGER_CRIPPLED 1
  #warning "Please update the compiler or add fmt, neam::cr::logger is crippled"
#endif

#include <vector>
#include <source_location>
#include <string>
#include "../spinlock.hpp"

#ifndef N_LOGGER_STRIP_DEBUG
  #define N_LOGGER_STRIP_DEBUG 0
#endif

namespace neam::cr
{
  class logger
  {
    public:
      enum class severity
      {
        debug,
        message,
        warning,
        error,
        critical,
      };

      severity min_severity = severity::debug;

      bool can_log(severity s) const
      {
        return (int)s >= (int)min_severity;
      }

      static const char* severity_to_str(severity s)
      {
        switch (s)
        {
          case severity::debug: return "debug";
          case severity::message: return "message";
          case severity::warning: return "warning";
          case severity::error: return "error";
          case severity::critical: return "critical";
        }
        return "unknown";
      }
      static const char* severity_abbr(severity s)
      {
        switch (s)
        {
          case severity::debug: return "DEBG";
          case severity::message: return "MESG";
          case severity::warning: return "WARN";
          case severity::error: return "ERR";
          case severity::critical: return "CRIT";
        }
        return "????";
      }

      void log_str(severity s, const std::string& str, std::source_location loc = std::source_location::current());

      std::lock_guard<spinlock> acquire_lock() { return std::lock_guard<spinlock>{lock}; }
      void wait_for_lock() { lock._wait_for_lock(); }

#if N_LOGGER_USE_FMT
      template<typename... Args> using format_string = fmt::format_string<Args...>;
#else
      template<typename... Args> using format_string = const char*;
#endif

#if N_LOGGER_USE_FMT
      template<typename... Args>
      void log_fmt(severity s, std::source_location loc, format_string<Args...> str, Args&&... args)
      {
        log_str(s, fmt::format(std::move(str), std::forward<Args>(args)...), loc);
      }
#elif !N_LOGGER_CRIPPLED
      template<typename... Args>
      void log_fmt(severity s, std::source_location loc, format_string<Args...> str, Args&&... args)
      {
        log_str(s, std::format(str, std::forward<Args>(args)...), loc);
      }
#else
      template<typename... Args>
      void log_fmt(severity s, std::source_location loc, format_string<Args...> str, Args&&... args)
      {
        log_str(s, str, loc);
      }
#endif

      struct log_location_helper
      {
        logger& output;
        const std::source_location loc;
        bool skip_lock = false;

        template<typename... Args>
        void log_fmt(severity s, format_string<Args...> str, Args&& ... args)
        {
          if (!output.can_log(s))
            return;
          if (!skip_lock)
            output.wait_for_lock();
          output.log_fmt(s, loc, str, std::forward<Args>(args)...);
        }

        // helpers:
        template<typename... Args>
        void debug(format_string<Args...> str, Args&& ... args)
        {
#if !N_LOGGER_STRIP_DEBUG
          output.log_fmt<Args...>(severity::debug, loc, std::move(str), std::forward<Args>(args)...);
#endif
        }
        template<typename... Args>
        void log(format_string<Args...> str, Args&& ... args)
        {
          output.log_fmt<Args...>(severity::message, loc, std::move(str), std::forward<Args>(args)...);
        }
        template<typename... Args>
        void warn(format_string<Args...> str, Args&& ... args)
        {
          output.log_fmt<Args...>(severity::warning, loc, std::move(str), std::forward<Args>(args)...);
        }
        template<typename... Args>
        void error(format_string<Args...> str, Args&& ... args)
        {
          output.log_fmt<Args...>(severity::error, loc, std::move(str), std::forward<Args>(args)...);
        }

        template<typename... Args>
        void critical(format_string<Args...> str, Args&& ... args)
        {
          output.log_fmt<Args...>(severity::critical, loc, std::move(str), std::forward<Args>(args)...);
        }
      };

      log_location_helper operator()(bool skip_lock = false, std::source_location loc = std::source_location::current())
      {
        return { *this, loc, skip_lock };
      }

      // callback handling:
      // callbacks are called for each logged message that pass the min_severity filter
      using callback_t = void(*)(void*, severity, const std::string&, std::source_location);

      void register_callback(callback_t cb, void* data);
      void unregister_callback(callback_t cb, void* data);

    private:
      struct callback_context
      {
        callback_t fnc;
        void* data;
      };
      std::vector<callback_context> callbacks;

      spinlock lock;
  };

  extern logger out;

  /// \brief Neat callback for cr::logger that prints the output to the console
  void print_log_to_console(void*, neam::cr::logger::severity s, const std::string& msg, std::source_location loc);

  /// \brief Uses the same format as print_log_to_console but returns a string instead
  std::string format_log_to_string(neam::cr::logger::severity s, const std::string& msg, std::source_location loc);
}
<commit_msg>Make the logger use the utility split string<commit_after>//
// created by : Timothée Feuillet
// date: 2021-11-24
//
//
// Copyright (c) 2021 Timothée Feuillet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#pragma once

#if __has_include(<fmt/format.h>)
  #define N_LOGGER_USE_FMT 1
  #define N_LOGGER_CRIPPLED 0
  #include <fmt/format.h>
#elif __has_include(<format>)
  #define N_LOGGER_USE_FMT 0
  #define N_LOGGER_CRIPPLED 0
  #include <format>
#else
  #define N_LOGGER_USE_FMT 0
  #define N_LOGGER_CRIPPLED 1
  #warning "Please update the compiler or add fmt, neam::cr::logger is crippled"
#endif

#include <vector>
#include <source_location>
#include <string>
#include "../spinlock.hpp"

#ifndef N_LOGGER_STRIP_DEBUG
  #define N_LOGGER_STRIP_DEBUG 0
#endif

namespace neam::cr
{
  class logger
  {
    public:
      enum class severity
      {
        debug,
        message,
        warning,
        error,
        critical,
      };

      severity min_severity = severity::debug;

      bool can_log(severity s) const
      {
        return (int)s >= (int)min_severity;
      }

      static const char* severity_to_str(severity s)
      {
        switch (s)
        {
          case severity::debug: return "debug";
          case severity::message: return "message";
          case severity::warning: return "warning";
          case severity::error: return "error";
          case severity::critical: return "critical";
        }
        return "unknown";
      }
      static const char* severity_abbr(severity s)
      {
        switch (s)
        {
          case severity::debug: return "DEBG";
          case severity::message: return "MESG";
          case severity::warning: return "WARN";
          case severity::error: return "ERR";
          case severity::critical: return "CRIT";
        }
        return "????";
      }

      void log_str(severity s, const std::string& str, std::source_location loc = std::source_location::current());

      std::lock_guard<spinlock> acquire_lock() { return std::lock_guard<spinlock>{lock}; }
      void wait_for_lock() { lock._wait_for_lock(); }

      struct log_location_helper
      {
        logger& output;
        const std::source_location loc;
        bool skip_lock = false;

#if N_LOGGER_USE_FMT
        template<typename... Args> using format_string = fmt::format_string<Args...>;
#else
        template<typename... Args> using format_string = const char*;
#endif

#if N_LOGGER_USE_FMT
        template<typename... Args>
        void log_fmt(severity s, std::source_location loc, format_string<Args...> str, Args&&... args)
        {
          output.log_str(s, fmt::format(std::move(str), std::forward<Args>(args)...), loc);
        }
#elif !N_LOGGER_CRIPPLED
        template<typename... Args>
        void log_fmt(severity s, std::source_location loc, format_string<Args...> str, Args&&... args)
        {
          output.log_str(s, std::format(str, std::forward<Args>(args)...), loc);
        }
#else
        template<typename... Args>
        void log_fmt(severity s, std::source_location loc, format_string<Args...> str, Args&&... args)
        {
          output.log_str(s, str, loc);
        }
#endif

        template<typename... Args>
        void log_fmt(severity s, format_string<Args...> str, Args&& ... args)
        {
          if (!output.can_log(s))
            return;
          if (!skip_lock)
            output.wait_for_lock();
          log_fmt(s, loc, str, std::forward<Args>(args)...);
        }

        // helpers:
        template<typename... Args>
        void debug(format_string<Args...> str, Args&& ... args)
        {
#if !N_LOGGER_STRIP_DEBUG
          log_fmt<Args...>(severity::debug, std::move(str), std::forward<Args>(args)...);
#endif
        }
        template<typename... Args>
        void log(format_string<Args...> str, Args&& ... args)
        {
          log_fmt<Args...>(severity::message, std::move(str), std::forward<Args>(args)...);
        }
        template<typename... Args>
        void warn(format_string<Args...> str, Args&& ... args)
        {
          log_fmt<Args...>(severity::warning, std::move(str), std::forward<Args>(args)...);
        }
        template<typename... Args>
        void error(format_string<Args...> str, Args&& ... args)
        {
          log_fmt<Args...>(severity::error, std::move(str), std::forward<Args>(args)...);
        }

        template<typename... Args>
        void critical(format_string<Args...> str, Args&& ... args)
        {
          log_fmt<Args...>(severity::critical, std::move(str), std::forward<Args>(args)...);
        }
      };

      log_location_helper operator()(bool skip_lock = false, std::source_location loc = std::source_location::current())
      {
        return { *this, loc, skip_lock };
      }

      // callback handling:
      // callbacks are called for each logged message that pass the min_severity filter
      using callback_t = void(*)(void*, severity, const std::string&, std::source_location);

      void register_callback(callback_t cb, void* data);
      void unregister_callback(callback_t cb, void* data);

    private:
      struct callback_context
      {
        callback_t fnc;
        void* data;
      };
      std::vector<callback_context> callbacks;

      spinlock lock;
  };

  extern logger out;

  /// \brief Neat callback for cr::logger that prints the output to the console
  void print_log_to_console(void*, neam::cr::logger::severity s, const std::string& msg, std::source_location loc);

  /// \brief Uses the same format as print_log_to_console but returns a string instead
  std::string format_log_to_string(neam::cr::logger::severity s, const std::string& msg, std::source_location loc);
}
<|endoftext|>


<commit_before>/*
** Copyright 2017 Centreon
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
** For more information : contact@centreon.com
*/
#include <algorithm>
#include <sstream>
#include <sstream>
#include "com/centreon/broker/exceptions/shutdown.hh"
#include "com/centreon/broker/io/events.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/lua/luabinding.hh"
#include "com/centreon/broker/lua/stream.hh"
#include "com/centreon/broker/misc/math.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::misc;
using namespace com::centreon::broker::lua;

/**************************************
 *                                     *
 *           Public Methods            *
 *                                     *
 **************************************/

/**
 *  Constructor.
 *
 *  @param[in] addr                    Address to connect to
 *  @param[in] port                    port
 */
stream::stream(std::string const& lua_script,
               std::map<std::string, misc::variant> const& conf_params,
               std::shared_ptr<persistent_cache> const& cache)
    : _cache{cache},
      _acks_count{0},
      _filter{0},
      _stats{{}},
      _stats_it{_stats.begin()},
      _next_stat{time(nullptr)},
      _nb_stats{0},
      _a_min{1},
      _exit{false} {

  bool fail = false;
  std::string fail_msg;

  /* The lua interpreter does not support exchanges with several threads from
   * the outside. By design, the filter is called from another thread than the
   * one used for the write function.
   * To fulfill this difficulty, the filter and write functions feed this thread
   * with their arguments. The filter waits for an answer whereas the write
   * function just increases an _acks_count to inform broker on treated events.
   */
  std::unique_lock<std::mutex> lock(_loop_m);

  _thread = std::thread([&] {
    // Access to the Lua interpreter
    luabinding* lb = nullptr;

    // If there is a filter, register it.
//    if (lb->has_filter()) {
//      std::function<bool(uint32_t)> func =
//          std::bind(&stream::filter, this, std::placeholders::_1);
//      multiplexing::muxer::register_read_filter(func);
//    }

    {
      std::lock_guard<std::mutex> lock(_loop_m);
      try {
        lb = new luabinding(lua_script, conf_params, _cache);
      }
      catch (std::exception const& e) {
        fail_msg = e.what();
        fail = true;
        _exit = true;
        _loop_cv.notify_one();
        return;
      }
      _loop_cv.notify_one();
    }

    std::unique_lock<std::mutex> lock(_loop_m);
    for (;;) {
      // count increases each time something is asked to be done
      _loop_cv.wait(lock, [this] { return _exit || _filter || !_events.empty(); });

      // No more commands are waiting, we can exit.
      if (!_filter && _events.empty())
        break;

      // Before working on events, we consider filter in priority.
//      if (_filter) {
//        lock.unlock();
//        {
//          std::lock_guard<std::mutex> ans_lock(_filter_m);
//          _filter_ok = lb->filter(_filter);
//          _filter = 0;
//          _filter_cv.notify_one();
//        }
//        lock.lock();
//      }

      if (!_events.empty()) {
        std::shared_ptr<io::data>& d = _events.front();
        _events.pop_front();
        lock.unlock();
        uint32_t res = lb->write(d);
        {
          std::lock_guard<std::mutex> lock(_acks_count_m);
          _acks_count += res;
        }
        lock.lock();
      }
    }

//    // Unregister the filter
//    multiplexing::muxer::unregister_read_filter();

    // No more need of the Lua interpreter
    delete lb;
  });

  _loop_cv.wait(lock);
  if (fail) {
    _thread.join();
    throw exceptions::msg() << fail_msg;
  }
}

/**
 *  Destructor.
 */
stream::~stream() {
  {
    std::lock_guard<std::mutex> lock(_loop_m);
    _exit = true;
    _loop_cv.notify_one();
  }
  if (_thread.joinable())
    _thread.join();
}

/**
 *  Read from the connector.
 *
 *  @param[out] d         Cleared.
 *  @param[in]  deadline  Timeout.
 *
 *  @return This method will throw.
 */
bool stream::read(std::shared_ptr<io::data>& d, time_t deadline) {
  (void)deadline;
  d.reset();
  throw exceptions::shutdown() << "cannot read from lua generic connector";
}

/**
 *  Write an event.
 *
 *  @param[in] data Event pointer.
 *
 *  @return Number of events acknowledged.
 */
int stream::write(std::shared_ptr<io::data> const& data) {
  if (!validate(data, "lua"))
    return 0;

  {
    std::lock_guard<std::mutex> lock(_loop_m);
    _events.push_back(data);

    time_t now = time(nullptr);
    if (now > _next_stat || std::isnan(_a)) {
      *_stats_it = {now, _events.size()};
      ++_nb_stats;
      ++_stats_it;
      if (_stats_it == _stats.end())
        _stats_it = _stats.begin();

      // We take a point at least every 30s.
      bool res = misc::least_squares(_stats, _nb_stats, _a, _b);
      if (!res) {
        _a = NAN;
        _b = NAN;
      }
      else {
        _next_stat += 30;
        if (_a > _a_min) {
          _a_min = _a;
          logging::debug(logging::high) << "LUA: The streamconnector looks "
            "quite slow, waiting events are increasing at the speed of "
            << _a << "events/s";
        }
      }
    }
  }
  _loop_cv.notify_one();

  {
    std::lock_guard<std::mutex> lock(_acks_count_m);
    int retval = _acks_count;
    _acks_count = 0;
    return retval;
  }
}

//bool stream::filter(uint32_t type) {
//  // Ask for a type
//  std::unique_lock<std::mutex> loop_lock(_loop_m);
//  _filter = type;
//  _loop_cv.notify_one();
//  loop_lock.unlock();
//
//  // Wait for the answer
//  std::unique_lock<std::mutex> ans_lock(_filter_m);
//  _filter_cv.wait(ans_lock, [this] { return _filter == 0; });
//  return _filter_ok;
//}

/**
 *  Events have been transmitted to the Lua connector, several of them have
 *  been treated and can now be acknowledged by broker. This function returns
 *  how many are in that case.
 *
 * @return The number of events to ack.
 */
int stream::flush() {
  std::lock_guard<std::mutex> lock(_acks_count_m);
  int retval = _acks_count;
  _acks_count = 0;
  return retval;
}

void stream::statistics(json11::Json::object& tree) const {
  std::lock_guard<std::mutex> lock(_loop_m);
  tree["waiting_events"] =
      json11::Json::object{{"lm", json11::Json::object{{"a", _a}, {"b", _b}}},
                           {"total", static_cast<double>(_events.size())}};
}
<commit_msg>fix(lua): fix build on debian arm. (#337)<commit_after>/*
** Copyright 2017 Centreon
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
** For more information : contact@centreon.com
*/
#include <algorithm>
#include <cmath>
#include <sstream>
#include <sstream>
#include "com/centreon/broker/exceptions/shutdown.hh"
#include "com/centreon/broker/io/events.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/lua/luabinding.hh"
#include "com/centreon/broker/lua/stream.hh"
#include "com/centreon/broker/misc/math.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::misc;
using namespace com::centreon::broker::lua;

/**************************************
 *                                     *
 *           Public Methods            *
 *                                     *
 **************************************/

/**
 *  Constructor.
 *
 *  @param[in] addr                    Address to connect to
 *  @param[in] port                    port
 */
stream::stream(std::string const& lua_script,
               std::map<std::string, misc::variant> const& conf_params,
               std::shared_ptr<persistent_cache> const& cache)
    : _cache{cache},
      _acks_count{0},
      _filter{0},
      _stats{{}},
      _stats_it{_stats.begin()},
      _next_stat{time(nullptr)},
      _nb_stats{0},
      _a_min{1},
      _exit{false} {

  bool fail = false;
  std::string fail_msg;

  /* The lua interpreter does not support exchanges with several threads from
   * the outside. By design, the filter is called from another thread than the
   * one used for the write function.
   * To fulfill this difficulty, the filter and write functions feed this thread
   * with their arguments. The filter waits for an answer whereas the write
   * function just increases an _acks_count to inform broker on treated events.
   */
  std::unique_lock<std::mutex> lock(_loop_m);

  _thread = std::thread([&] {
    // Access to the Lua interpreter
    luabinding* lb = nullptr;

    // If there is a filter, register it.
//    if (lb->has_filter()) {
//      std::function<bool(uint32_t)> func =
//          std::bind(&stream::filter, this, std::placeholders::_1);
//      multiplexing::muxer::register_read_filter(func);
//    }

    {
      std::lock_guard<std::mutex> lock(_loop_m);
      try {
        lb = new luabinding(lua_script, conf_params, _cache);
      }
      catch (std::exception const& e) {
        fail_msg = e.what();
        fail = true;
        _exit = true;
        _loop_cv.notify_one();
        return;
      }
      _loop_cv.notify_one();
    }

    std::unique_lock<std::mutex> lock(_loop_m);
    for (;;) {
      // count increases each time something is asked to be done
      _loop_cv.wait(lock, [this] { return _exit || _filter || !_events.empty(); });

      // No more commands are waiting, we can exit.
      if (!_filter && _events.empty())
        break;

      // Before working on events, we consider filter in priority.
//      if (_filter) {
//        lock.unlock();
//        {
//          std::lock_guard<std::mutex> ans_lock(_filter_m);
//          _filter_ok = lb->filter(_filter);
//          _filter = 0;
//          _filter_cv.notify_one();
//        }
//        lock.lock();
//      }

      if (!_events.empty()) {
        std::shared_ptr<io::data>& d = _events.front();
        _events.pop_front();
        lock.unlock();
        uint32_t res = lb->write(d);
        {
          std::lock_guard<std::mutex> lock(_acks_count_m);
          _acks_count += res;
        }
        lock.lock();
      }
    }

//    // Unregister the filter
//    multiplexing::muxer::unregister_read_filter();

    // No more need of the Lua interpreter
    delete lb;
  });

  _loop_cv.wait(lock);
  if (fail) {
    _thread.join();
    throw exceptions::msg() << fail_msg;
  }
}

/**
 *  Destructor.
 */
stream::~stream() {
  {
    std::lock_guard<std::mutex> lock(_loop_m);
    _exit = true;
    _loop_cv.notify_one();
  }
  if (_thread.joinable())
    _thread.join();
}

/**
 *  Read from the connector.
 *
 *  @param[out] d         Cleared.
 *  @param[in]  deadline  Timeout.
 *
 *  @return This method will throw.
 */
bool stream::read(std::shared_ptr<io::data>& d, time_t deadline) {
  (void)deadline;
  d.reset();
  throw exceptions::shutdown() << "cannot read from lua generic connector";
}

/**
 *  Write an event.
 *
 *  @param[in] data Event pointer.
 *
 *  @return Number of events acknowledged.
 */
int stream::write(std::shared_ptr<io::data> const& data) {
  if (!validate(data, "lua"))
    return 0;

  {
    std::lock_guard<std::mutex> lock(_loop_m);
    _events.push_back(data);

    time_t now = time(nullptr);
    if (now > _next_stat || std::isnan(_a)) {
      *_stats_it = {now, _events.size()};
      ++_nb_stats;
      ++_stats_it;
      if (_stats_it == _stats.end())
        _stats_it = _stats.begin();

      // We take a point at least every 30s.
      bool res = misc::least_squares(_stats, _nb_stats, _a, _b);
      if (!res) {
        _a = NAN;
        _b = NAN;
      }
      else {
        _next_stat += 30;
        if (_a > _a_min) {
          _a_min = _a;
          logging::debug(logging::high) << "LUA: The streamconnector looks "
            "quite slow, waiting events are increasing at the speed of "
            << _a << "events/s";
        }
      }
    }
  }
  _loop_cv.notify_one();

  {
    std::lock_guard<std::mutex> lock(_acks_count_m);
    int retval = _acks_count;
    _acks_count = 0;
    return retval;
  }
}

//bool stream::filter(uint32_t type) {
//  // Ask for a type
//  std::unique_lock<std::mutex> loop_lock(_loop_m);
//  _filter = type;
//  _loop_cv.notify_one();
//  loop_lock.unlock();
//
//  // Wait for the answer
//  std::unique_lock<std::mutex> ans_lock(_filter_m);
//  _filter_cv.wait(ans_lock, [this] { return _filter == 0; });
//  return _filter_ok;
//}

/**
 *  Events have been transmitted to the Lua connector, several of them have
 *  been treated and can now be acknowledged by broker. This function returns
 *  how many are in that case.
 *
 * @return The number of events to ack.
 */
int stream::flush() {
  std::lock_guard<std::mutex> lock(_acks_count_m);
  int retval = _acks_count;
  _acks_count = 0;
  return retval;
}

void stream::statistics(json11::Json::object& tree) const {
  std::lock_guard<std::mutex> lock(_loop_m);
  tree["waiting_events"] =
      json11::Json::object{{"lm", json11::Json::object{{"a", _a}, {"b", _b}}},
                           {"total", static_cast<double>(_events.size())}};
}
<|endoftext|>


<commit_before>#include "ride/runner.h"
#include <wx/utils.h>
#include <wx/process.h>
#include <wx/txtstrm.h>

#include "ride/mainwindow.h"

class PipedProcess;
class AsyncProcess;

WX_DEFINE_ARRAY_PTR(PipedProcess*, PipedProcessesArray);
WX_DEFINE_ARRAY_PTR(AsyncProcess*, AsyncProcessesArray);

struct Runner::Pimpl {
  Pimpl();
  void Append(const wxString&) {}
  void AddPipedProcess(PipedProcess *process);
  void OnPipedProcessTerminated(PipedProcess *process);
  void OnAsyncProcessTerminated(AsyncProcess *process);

  int RunCmd(const wxString& root, const wxString& cmd);

  PipedProcessesArray piped_running_processes_;
  AsyncProcessesArray async_running_processes_;
};

Runner::Pimpl::Pimpl() {
}

class AsyncProcess : public wxProcess
{
public:
  AsyncProcess(Runner::Pimpl* project, const wxString& cmd)
    : wxProcess(), cmd_(cmd)
  {
    project_ = project;
  }

  virtual void OnTerminate(int pid, int status) {
    project_->Append(wxString::Format(wxT("Process %u ('%s') terminated with exit code %d."),
      pid, cmd_.c_str(), status));
    project_->Append("");
    project_->OnAsyncProcessTerminated(this);
  }

protected:
  Runner::Pimpl *project_;
  wxString cmd_;
};

class PipedProcess : public AsyncProcess
{
public:
  PipedProcess(Runner::Pimpl *project, const wxString& cmd)
    : AsyncProcess(project, cmd)
  {
    Redirect();
  }

  virtual void OnTerminate(int pid, int status) {
    // show the rest of the output
    while (HasInput()) { }
    project_->OnPipedProcessTerminated(this);
    AsyncProcess::OnTerminate(pid, status);
  }

  virtual bool HasInput() {
    bool hasInput = false;

    if (IsInputAvailable())
    {
      wxTextInputStream tis(*GetInputStream());
      const wxString msg = tis.ReadLine(); // this assumes that the output is always line buffered
      project_->Append(msg);
      hasInput = true;
    }

    if (IsErrorAvailable())
    {
      wxTextInputStream tis(*GetErrorStream());
      const wxString msg = tis.ReadLine(); // this assumes that the output is always line buffered
      project_->Append(msg);
      hasInput = true;
    }

    return hasInput;
  }
};

int Runner::Pimpl::RunCmd(const wxString& root, const wxString& cmd) {
  bool async = true;

  PipedProcess* process = new PipedProcess(this, cmd);
  Append("> " + cmd);

  wxExecuteEnv env;
  env.cwd = root;

  const int flags = async
    ? wxEXEC_ASYNC | wxEXEC_SHOW_CONSOLE
    : wxEXEC_SYNC | wxEXEC_SHOW_CONSOLE;

  const int execute_result = wxExecute(cmd, flags, process, &env);

  if (async) {
    // async call
    if (!execute_result) {
      Append(wxString::Format(wxT("Execution of '%s' failed."), cmd.c_str()));
      delete process;
    }
    else {
      AddPipedProcess(process);
    }
  }
  else {
    // sync call, remove process
    delete process;
  }

  return execute_result;
}

void Runner::Pimpl::AddPipedProcess(PipedProcess *process)
{
  piped_running_processes_.Add(process);
  async_running_processes_.Add(process);
}

void Runner::Pimpl::OnPipedProcessTerminated(PipedProcess *process)
{
  piped_running_processes_.Remove(process);
}

void Runner::Pimpl::OnAsyncProcessTerminated(AsyncProcess *process)
{
  async_running_processes_.Remove(process);
  delete process;
}

//////////////////////////////////////////////////////////////////////////

Runner::Runner() {
}
Runner::~Runner() {
}

bool Runner::RunCmd(const wxString& root, const wxString& cmd) {
  return false;
}
bool Runner::IsRunning() const {
  return true;
}
int Runner::GetExitCode() {
  return -1;
}

<commit_msg>single running process<commit_after>#include "ride/runner.h"
#include <wx/utils.h>
#include <wx/process.h>
#include <wx/txtstrm.h>

#include "ride/mainwindow.h"

class PipedProcess;
class AsyncProcess;

struct Runner::Pimpl {
  Pimpl() : piped_running_processes_(0), async_running_processes_(0) {
  }

  void Append(const wxString&) {}
  void AddPipedProcess(PipedProcess *process);
  void OnPipedProcessTerminated(PipedProcess *process);
  void OnAsyncProcessTerminated(AsyncProcess *process);

  int RunCmd(const wxString& root, const wxString& cmd);

  PipedProcess* piped_running_processes_;
  AsyncProcess* async_running_processes_;
};

class AsyncProcess : public wxProcess
{
public:
  AsyncProcess(Runner::Pimpl* project, const wxString& cmd)
    : wxProcess(), cmd_(cmd)
  {
    project_ = project;
  }

  virtual void OnTerminate(int pid, int status) {
    project_->Append(wxString::Format(wxT("Process %u ('%s') terminated with exit code %d."),
      pid, cmd_.c_str(), status));
    project_->Append("");
    project_->OnAsyncProcessTerminated(this);
  }

protected:
  Runner::Pimpl *project_;
  wxString cmd_;
};

class PipedProcess : public AsyncProcess
{
public:
  PipedProcess(Runner::Pimpl *project, const wxString& cmd)
    : AsyncProcess(project, cmd)
  {
    Redirect();
  }

  virtual void OnTerminate(int pid, int status) {
    // show the rest of the output
    while (HasInput()) { }
    project_->OnPipedProcessTerminated(this);
    AsyncProcess::OnTerminate(pid, status);
  }

  virtual bool HasInput() {
    bool hasInput = false;

    if (IsInputAvailable())
    {
      wxTextInputStream tis(*GetInputStream());
      const wxString msg = tis.ReadLine(); // this assumes that the output is always line buffered
      project_->Append(msg);
      hasInput = true;
    }

    if (IsErrorAvailable())
    {
      wxTextInputStream tis(*GetErrorStream());
      const wxString msg = tis.ReadLine(); // this assumes that the output is always line buffered
      project_->Append(msg);
      hasInput = true;
    }

    return hasInput;
  }
};

int Runner::Pimpl::RunCmd(const wxString& root, const wxString& cmd) {
  bool async = true;

  PipedProcess* process = new PipedProcess(this, cmd);
  Append("> " + cmd);

  wxExecuteEnv env;
  env.cwd = root;

  const int flags = async
    ? wxEXEC_ASYNC | wxEXEC_SHOW_CONSOLE
    : wxEXEC_SYNC | wxEXEC_SHOW_CONSOLE;

  const int execute_result = wxExecute(cmd, flags, process, &env);

  if (async) {
    // async call
    if (!execute_result) {
      Append(wxString::Format(wxT("Execution of '%s' failed."), cmd.c_str()));
      delete process;
    }
    else {
      AddPipedProcess(process);
    }
  }
  else {
    // sync call, remove process
    delete process;
  }

  return execute_result;
}

void Runner::Pimpl::AddPipedProcess(PipedProcess *process)
{
  assert(piped_running_processes_ == NULL);
  assert(async_running_processes_ == NULL);
  piped_running_processes_ = process;
  async_running_processes_ = process;
}

void Runner::Pimpl::OnPipedProcessTerminated(PipedProcess *process)
{
  assert(piped_running_processes_ == process);
  piped_running_processes_ = NULL;
}

void Runner::Pimpl::OnAsyncProcessTerminated(AsyncProcess *process)
{
  assert(async_running_processes_ == process);
  async_running_processes_ = process;
  delete process;
}

//////////////////////////////////////////////////////////////////////////

Runner::Runner() : pimpl(new Pimpl()) {
}
Runner::~Runner() {
}

bool Runner::RunCmd(const wxString& root, const wxString& cmd) {
  return false;
}
bool Runner::IsRunning() const {
  return true;
}
int Runner::GetExitCode() {
  return -1;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cachestr.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 14:33:30 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <debug.hxx>
#include <stream.hxx>
#include <cachestr.hxx>
#include <tempfile.hxx>

/*************************************************************************
|*
|*    SvCacheStream::SvCacheStream()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

SvCacheStream::SvCacheStream( ULONG nMaxMemSize )
{
    if( !nMaxMemSize )
#if defined WIN || defined WNT || defined OS2 || defined MAC || defined UNX
        nMaxMemSize = 20480;
#else
        nMaxMemSize = 20480;
#endif
    SvStream::bIsWritable = TRUE;
    nMaxSize        = nMaxMemSize;
    bPersistent     = FALSE;
    pSwapStream     = 0;
    pCurrentStream  = new SvMemoryStream( nMaxMemSize );
    pTempFile       = 0;
}

/*************************************************************************
|*
|*    SvCacheStream::SvCacheStream()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

SvCacheStream::SvCacheStream( const String &rFileName,
                              ULONG nExpectedSize,
                              ULONG nMaxMemSize )
{
    if( !nMaxMemSize )
#if defined WIN || defined WNT || defined OS2 || defined MAC || defined UNX
        nMaxMemSize = 20480;
#else
        nMaxMemSize = 20480;
#endif

    if( nExpectedSize > nMaxMemSize )
        nExpectedSize = nMaxMemSize; // oder gleich in File schreiben
    else if( !nExpectedSize )
        nExpectedSize = 4096;

    SvStream::bIsWritable = TRUE;
    nMaxSize        = nMaxMemSize;
    bPersistent     = TRUE;
    aFileName       = rFileName;
    pSwapStream     = 0;
    pCurrentStream  = new SvMemoryStream( nExpectedSize );
    pTempFile       = 0;
}

/*************************************************************************
|*
|*    SvCacheStream::~SvCacheStream()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

SvCacheStream::~SvCacheStream()
{
       if( pCurrentStream != pSwapStream )
        delete pSwapStream;
    delete pCurrentStream;

    if( pSwapStream && !bPersistent && pTempFile )
    {
        // temporaeres File loeschen
        pTempFile->EnableKillingFile( TRUE );
    }

    delete pTempFile;
}

/*************************************************************************
|*
|*    SvCacheStream::SwapOut()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

void SvCacheStream::SwapOut()
{
    if( pCurrentStream != pSwapStream )
    {
        if( !pSwapStream && !aFileName.Len() )
        {
            if (aFilenameLinkHdl.IsSet())
            {
                // pSwapStream wird zum Schutz gegen Reentranz genutzt
                pSwapStream = pCurrentStream;
                Link aLink( aFilenameLinkHdl );
                aFilenameLinkHdl = Link();
                aLink.Call(this);
                // pSwapStream nur zuruecksetzen, wenn nicht ueber
                // SetSwapStream geaendert
                if( pSwapStream == pCurrentStream ) pSwapStream = 0;
            }
            else
            {
                pTempFile = new TempFile;
                aFileName = pTempFile->GetName();
            }
        }

        ULONG nPos = pCurrentStream->Tell();
        pCurrentStream->Seek( 0 );
        if( !pSwapStream )
            pSwapStream = new SvFileStream( aFileName, STREAM_READWRITE | STREAM_TRUNC );
        *pSwapStream << *pCurrentStream;
        pSwapStream->Flush();
        delete pCurrentStream;
        pCurrentStream = pSwapStream;
        pCurrentStream->Seek( nPos );
    }
}

/*************************************************************************
|*
|*    SvCacheStream::GetData()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

ULONG SvCacheStream::GetData( void* pData, ULONG nSize )
{
    return pCurrentStream->Read( pData, nSize );
}

/*************************************************************************
|*
|*    SvCacheStream::PutData()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

ULONG SvCacheStream::PutData( const void* pData, ULONG nSize )
{
    // lieber unnoetig auslagern als unnoetig umkopieren
    if( pCurrentStream != pSwapStream
        && pCurrentStream->Tell() + nSize > nMaxSize )
        SwapOut();
    return pCurrentStream->Write( pData, nSize );
}

/*************************************************************************
|*
|*    SvCacheStream::SeekPos()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

ULONG SvCacheStream::SeekPos( ULONG nPos )
{
    return pCurrentStream->Seek( nPos );
}

/*************************************************************************
|*
|*    SvCacheStream::FlushData()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

void SvCacheStream::FlushData()
{
    pCurrentStream->Flush();
    if( pCurrentStream != pSwapStream
        && ((SvMemoryStream*)pCurrentStream)->GetSize() > nMaxSize )
        SwapOut();
}

/*************************************************************************
|*
|*    SvCacheStream::GetStr()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

const void* SvCacheStream::GetBuffer()
{
    Flush();
    if( pCurrentStream != pSwapStream )
        return ((SvMemoryStream*)pCurrentStream)->GetData();
    else
        return 0;
}

/*************************************************************************
|*
|*    SvCacheStream::SetSize()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

void SvCacheStream::SetSize( ULONG nSize )
{
    pCurrentStream->SetStreamSize( nSize );
}

/*************************************************************************
|*
|*    SvCacheStream::GetSize()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

ULONG SvCacheStream::GetSize()
{
    // ACHTUNG: SvMemoryStream::GetSize() gibt Groesse
    // des allozierten Buffers zurueck
    Flush();
    ULONG nTemp = Tell();
    ULONG nLength = Seek( STREAM_SEEK_TO_END );
    Seek( nTemp );
    return nLength;
}

void    SvCacheStream::SetFilenameHdl( const Link& rLink)
{
    aFilenameLinkHdl = rLink;
}

const Link& SvCacheStream::GetFilenameHdl() const
{
    return aFilenameLinkHdl;
}
<commit_msg>INTEGRATION: CWS warnings01 (1.2.8); FILE MERGED 2005/10/13 13:24:30 sb 1.2.8.1: #i53898# Removed code for obsolete platforms.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cachestr.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 13:50:35 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <debug.hxx>
#include <stream.hxx>
#include <cachestr.hxx>
#include <tempfile.hxx>

/*************************************************************************
|*
|*    SvCacheStream::SvCacheStream()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

SvCacheStream::SvCacheStream( ULONG nMaxMemSize )
{
    if( !nMaxMemSize )
        nMaxMemSize = 20480;
    SvStream::bIsWritable = TRUE;
    nMaxSize        = nMaxMemSize;
    bPersistent     = FALSE;
    pSwapStream     = 0;
    pCurrentStream  = new SvMemoryStream( nMaxMemSize );
    pTempFile       = 0;
}

/*************************************************************************
|*
|*    SvCacheStream::SvCacheStream()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

SvCacheStream::SvCacheStream( const String &rFileName,
                              ULONG nExpectedSize,
                              ULONG nMaxMemSize )
{
    if( !nMaxMemSize )
        nMaxMemSize = 20480;

    if( nExpectedSize > nMaxMemSize )
        nExpectedSize = nMaxMemSize; // oder gleich in File schreiben
    else if( !nExpectedSize )
        nExpectedSize = 4096;

    SvStream::bIsWritable = TRUE;
    nMaxSize        = nMaxMemSize;
    bPersistent     = TRUE;
    aFileName       = rFileName;
    pSwapStream     = 0;
    pCurrentStream  = new SvMemoryStream( nExpectedSize );
    pTempFile       = 0;
}

/*************************************************************************
|*
|*    SvCacheStream::~SvCacheStream()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

SvCacheStream::~SvCacheStream()
{
       if( pCurrentStream != pSwapStream )
        delete pSwapStream;
    delete pCurrentStream;

    if( pSwapStream && !bPersistent && pTempFile )
    {
        // temporaeres File loeschen
        pTempFile->EnableKillingFile( TRUE );
    }

    delete pTempFile;
}

/*************************************************************************
|*
|*    SvCacheStream::SwapOut()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

void SvCacheStream::SwapOut()
{
    if( pCurrentStream != pSwapStream )
    {
        if( !pSwapStream && !aFileName.Len() )
        {
            if (aFilenameLinkHdl.IsSet())
            {
                // pSwapStream wird zum Schutz gegen Reentranz genutzt
                pSwapStream = pCurrentStream;
                Link aLink( aFilenameLinkHdl );
                aFilenameLinkHdl = Link();
                aLink.Call(this);
                // pSwapStream nur zuruecksetzen, wenn nicht ueber
                // SetSwapStream geaendert
                if( pSwapStream == pCurrentStream ) pSwapStream = 0;
            }
            else
            {
                pTempFile = new TempFile;
                aFileName = pTempFile->GetName();
            }
        }

        ULONG nPos = pCurrentStream->Tell();
        pCurrentStream->Seek( 0 );
        if( !pSwapStream )
            pSwapStream = new SvFileStream( aFileName, STREAM_READWRITE | STREAM_TRUNC );
        *pSwapStream << *pCurrentStream;
        pSwapStream->Flush();
        delete pCurrentStream;
        pCurrentStream = pSwapStream;
        pCurrentStream->Seek( nPos );
    }
}

/*************************************************************************
|*
|*    SvCacheStream::GetData()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

ULONG SvCacheStream::GetData( void* pData, ULONG nSize )
{
    return pCurrentStream->Read( pData, nSize );
}

/*************************************************************************
|*
|*    SvCacheStream::PutData()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

ULONG SvCacheStream::PutData( const void* pData, ULONG nSize )
{
    // lieber unnoetig auslagern als unnoetig umkopieren
    if( pCurrentStream != pSwapStream
        && pCurrentStream->Tell() + nSize > nMaxSize )
        SwapOut();
    return pCurrentStream->Write( pData, nSize );
}

/*************************************************************************
|*
|*    SvCacheStream::SeekPos()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

ULONG SvCacheStream::SeekPos( ULONG nPos )
{
    return pCurrentStream->Seek( nPos );
}

/*************************************************************************
|*
|*    SvCacheStream::FlushData()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

void SvCacheStream::FlushData()
{
    pCurrentStream->Flush();
    if( pCurrentStream != pSwapStream
        && ((SvMemoryStream*)pCurrentStream)->GetSize() > nMaxSize )
        SwapOut();
}

/*************************************************************************
|*
|*    SvCacheStream::GetStr()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

const void* SvCacheStream::GetBuffer()
{
    Flush();
    if( pCurrentStream != pSwapStream )
        return ((SvMemoryStream*)pCurrentStream)->GetData();
    else
        return 0;
}

/*************************************************************************
|*
|*    SvCacheStream::SetSize()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

void SvCacheStream::SetSize( ULONG nSize )
{
    pCurrentStream->SetStreamSize( nSize );
}

/*************************************************************************
|*
|*    SvCacheStream::GetSize()
|*
|*    Beschreibung      STREAM.SDW
|*    Ersterstellung    OV 27.09.94
|*    Letzte Aenderung  OV 27.09.94
|*
*************************************************************************/

ULONG SvCacheStream::GetSize()
{
    // ACHTUNG: SvMemoryStream::GetSize() gibt Groesse
    // des allozierten Buffers zurueck
    Flush();
    ULONG nTemp = Tell();
    ULONG nLength = Seek( STREAM_SEEK_TO_END );
    Seek( nTemp );
    return nLength;
}

void    SvCacheStream::SetFilenameHdl( const Link& rLink)
{
    aFilenameLinkHdl = rLink;
}

const Link& SvCacheStream::GetFilenameHdl() const
{
    return aFilenameLinkHdl;
}
<|endoftext|>