From 1594e806c48c587e0af5076d114219190a5f5fc0 Mon Sep 17 00:00:00 2001 From: hama Date: Sun, 18 Jan 2015 12:23:01 +0100 Subject: [PATCH] Refactoring ReRandomizer, fix in ReStringList::readFromFile() --- base/ReByteBuffer.cpp | 54 +++++++- base/ReByteBuffer.hpp | 5 +- base/ReProgramArgs.cpp | 1 - base/ReStringList.cpp | 140 ++++++++++----------- base/ReStringList.hpp | 3 +- base/ReTestUnit.cpp | 111 +++++++++++----- base/ReTestUnit.hpp | 8 +- base/ReVarArgs.cpp | 2 +- base/rebase.hpp | 5 +- cunit/cuReByteBuffer.cpp | 26 +++- cunit/cuReDirectory.cpp | 3 +- cunit/{cuHashList.cpp => cuReHashList.cpp} | 2 + cunit/cuReProgramArgs.cpp | 80 +++++++++++- cunit/cuReRandomizer.cpp | 49 ++++++++ cunit/cuReStringList.cpp | 17 ++- cunit/cuReTest.cpp | 31 +++-- cunit/cuReTraverser.cpp | 5 +- cunit/cuReconfig.cpp | 3 +- cunit/testall.cpp | 12 +- math/ReRandomizer.cpp | 97 +++++++++++--- math/ReRandomizer.hpp | 30 +++-- math/remath.hpp | 5 +- 22 files changed, 524 insertions(+), 165 deletions(-) rename cunit/{cuHashList.cpp => cuReHashList.cpp} (96%) create mode 100644 cunit/cuReRandomizer.cpp diff --git a/base/ReByteBuffer.cpp b/base/ReByteBuffer.cpp index c44ef3f..4e18366 100644 --- a/base/ReByteBuffer.cpp +++ b/base/ReByteBuffer.cpp @@ -161,6 +161,40 @@ ReByteBuffer& ReByteBuffer::appendInt(int number, const char* format){ ReByteBuffer& ReByteBuffer::append(const ReByteBuffer& source){ return append(source.str(), source.length()); } +/** @brief Appends a time (given in milli seconds) as 'dd:HH:MM.mmm'. + * + * @param time the time (duration) in msec + * @param minLength > 5: seconds will be 2 digits (preceeding '0' if needed)
+ * > 6: at least MM:SS.sss
+ * > 9: at least HH:MM:SS.sss
+ * > 12: at least dd:HH:MM:SS.sss
+ * @return buffer (for chaining) + */ +ReByteBuffer& ReByteBuffer::appendMilliSec(int time, int minLength){ + int days = time / (24 * 3600 * 1000LL); + time %= 24 * 3600 * 1000; + int expectedLength = days > 0 ? 12 : 0; + int hours = time / (3600 * 1000); + time %= 3600 * 1000; + if (hours > 0 && expectedLength == 0) + expectedLength = 9; + int minutes = time / (60 * 1000); + time %= 60 * 1000; + if (minutes > 0 && expectedLength == 0) + expectedLength = 5; + int minimum = minLength > expectedLength ? minLength : expectedLength; + int sec = time / 1000; + int msec = time % 1000; + static const char* stdFormat = "%02d"; + if (days > 0 || minimum > 12) + appendInt(days).append(":"); + if (hours > 0 || minimum > 9) + appendInt(hours, stdFormat).append(":"); + if (minutes > 0 || minimum > 6) + appendInt(minutes, stdFormat).append(":"); + appendInt(sec, sec > 10 || minimum > 5 ? stdFormat : "%d").append("."); + appendInt(msec, "%03d"); +} /** Converts a subsequence into an integer. * @@ -261,6 +295,24 @@ void ReByteBuffer::ensureSize(size_t size){ m_capacity = size; } } +/** + * @brief Fills a part of the buffer with a given character. + * + * @param filler the byte which is used as filler + * @param start the first index to fill. 0 <= start < m_length + * @param end the index behind the last filled position. May be behind m_length + * @return the instance itself (vor chaining) + */ +ReByteBuffer& ReByteBuffer::fill(Byte filler, int start, int end){ + if (end == -1) + end = m_length; + if (start >= 0 && start < end){ + if (end > m_length) + setLength(end); + memset(m_buffer + start, filler, end - start); + } + return *this; +} /** @brief Checks for the index of the first different byte. * @@ -454,7 +506,7 @@ ReByteBuffer& ReByteBuffer::setLength(size_t length){ * will be filled with this value * @return *this (for chaining) */ -ReByteBuffer& ReByteBuffer::setLengthAndFill(size_t length, Byte filler){ +ReByteBuffer& ReByteBuffer::setLengthAndFillOut(size_t length, Byte filler){ ensureSize(length); if (length > m_length) memset(m_buffer + m_length, filler, length - m_length); diff --git a/base/ReByteBuffer.hpp b/base/ReByteBuffer.hpp index aa6f891..e4df448 100644 --- a/base/ReByteBuffer.hpp +++ b/base/ReByteBuffer.hpp @@ -45,6 +45,7 @@ public: ReByteBuffer& append(const Byte* source, size_t length = -1); ReByteBuffer& append(const ReByteBuffer& source); ReByteBuffer& appendInt(int number, const char* format = "%d"); + ReByteBuffer& appendMilliSec(int time, int minLength = 5); /** @brief Returns the n-th byte of the internal buffer. * @param index The index of the wanted byte. * @return 0: Wrong index. Otherwise: The byte from the wanted position. @@ -83,6 +84,7 @@ public: bool rc = buffer.length() == m_length && _memcmp(buffer.str(), m_buffer, m_length) == 0; return rc; } + ReByteBuffer& fill(Byte filler = 0, int start = 0, int end = -1); int firstDifference(const Byte* source, size_t length, int start = 0, bool ignoreCase = false); /** @brief Finds the index of the first occurrence of a given byte. * @param toFind This byte will be searched. @@ -158,8 +160,7 @@ public: } void setDelta(int delta); ReByteBuffer& setLength(size_t length); - ReByteBuffer& setLengthAndFill(size_t length, Byte filler = 0); - + ReByteBuffer& setLengthAndFillOut(size_t length, Byte filler = 0); bool splice(size_t ix, size_t replacedLength, const Byte* source, size_t length); bool startsWith(const Byte* head, size_t headLength = -1, const bool ignoreCase = false) const; diff --git a/base/ReProgramArgs.cpp b/base/ReProgramArgs.cpp index 3f82448..7bf6cee 100644 --- a/base/ReProgramArgs.cpp +++ b/base/ReProgramArgs.cpp @@ -334,7 +334,6 @@ void ReProgramArgs::search(char shortName, const char* longName, } while (! found && m_properties.next(position, &name, &properties)){ const char* ptr = properties.str(); - printf("%s\n", ptr); list.split(properties.str(), '\1'); if (longName == NULL && list.count() > IxShort && shortName == list.strOf(IxShort)[0]) found = true; diff --git a/base/ReStringList.cpp b/base/ReStringList.cpp index 52dc481..2acae52 100644 --- a/base/ReStringList.cpp +++ b/base/ReStringList.cpp @@ -21,11 +21,11 @@ ReStringList::ReStringList(int deltaList, int deltaBuffer) : */ ReStringList::~ReStringList() { } -/** @brief Appends a string at the end. +/** @brief Appends a string at the end * - * @param source The new string. + * @param source the new string * @param tagOf An item which will stored with the string. It can be retrieved - * by the same index.This class knows nothing about this. + * by the same index.This class knows nothing about this * @return the instance itself (for chaining) */ ReStringList& ReStringList::append(const char* source, Tag tagOf){ @@ -34,65 +34,65 @@ ReStringList& ReStringList::append(const char* source, Tag tagOf){ } /** @brief Appends a string at the end. * - * @param source The new string. + * @param source the new string * @param tagOf An item which will stored with the string. It can be retrieved - * by the same index.This class knows nothing about this. + * by the same index.This class knows nothing about this * @return the instance itself (for chaining) */ ReStringList& ReStringList::append(const ReByteBuffer& source, Tag tagOf){ - add(-1, source.str(), source.length() + 1, tagOf); + int ix = add(-1, source.str(), source.length() + 1, tagOf); return *this; } /** @brief Appends a stringlist at the end. * - * @param source The new stringlist. + * @param source the new stringlist * @return the instance itself (for chaining) */ ReStringList& ReStringList::append(const ReStringList& source){ for (size_t ii = 0; ii < source.count(); ii++) - add(-1, source.strOf(ii), source.sizeOf(ii), source.tagOf(ii)); + add(-1, source.strOf(ii), source.strLengthOf(ii), source.tagOf(ii)); return *this; } /** @brief Inserts a string at a given index. * * If the index exceeds the length of the array it will be appended. * - * @param source The new string. - * @param tagOf An item which will stored with the string. It can be retrieved by the same index. - * This class knows nothing about this. + * @param source the new string + * @param tagOf an item which will stored with the string. It can be retrieved by the same index. + * This class knows nothing about this */ void ReStringList::insert(Index index, const char* source, Tag tagOf){ add(index, source, strlen(source) + 1, tagOf); } /** @brief Replaces an element in the internal array: a string and a tagOf. * - * @param index The element with this index will be replaced. - * @param source The new string of the replaced element. - * @param tagOf The tagOf of the replace element. + * @param index the element with this index will be replaced + * @param source the new string of the replaced element + * @param tagOf the tagOf of the replace element */ void ReStringList::replace(Index index, const char* source, Tag tagOf){ - set(index, source, strlen(source), tagOf); + set(index, source, strlen(source) + 1, tagOf); } /** @brief Replaces a string in the internal array. * * The tagOf of the element remains unchanged. * - * @param index The element with this index will be replaced. - * @param source The new string of the replaced element. + * @param index the element with this index will be replaced + * @param source the new string of the replaced element */ void ReStringList::replaceString(Index index, const char* source){ if (index < count()){ Sequence* seq = getInfo(index); - set(index, source, strlen(source), seq->m_tag); + set(index, source, strlen(source) + 1, seq->m_tag); } } /** @brief Replaces a tagOf in the internal array. * * The string of the element remains unchanged. * - * @param index The element with this index will be replaced. - * @param source The new string of the replaced element. + * @param index the element with this index will be replaced + * @param source the new string of the replaced element */ void ReStringList::replaceTag(Index index, Tag tagOf){ if (index < count()){ @@ -103,10 +103,10 @@ void ReStringList::replaceTag(Index index, Tag tagOf){ /** @brief Returns the C string given by an index. * - * @param index The index of the wanted string. + * @param index the index of the wanted string * - * @return NULL: The index is too large. - * Otherwise: The wanted string. + * @return NULL: the index is too large. + * Otherwise: the wanted string */ const char* ReStringList::strOf(Index index) const{ const char* rc = NULL; @@ -120,10 +120,10 @@ const char* ReStringList::strOf(Index index) const{ * * A tagOf is an additional info stored with the string. * - * @param index The index of the wanted tagOf. + * @param index the index of the wanted tagOf * - * @return -1: The index is too large. - * Otherwise: The wanted tagOf. + * @return -1: the index is too large.
+ * Otherwise: the wanted tag */ ReSeqArray::Tag ReStringList::tagOf(Index index) const{ Tag rc = -1; @@ -135,11 +135,11 @@ ReSeqArray::Tag ReStringList::tagOf(Index index) const{ } /** @brief Returns the length of the byte sequence given by an index. * - * @param index The index of the wanted string length. + * @param index the index of the wanted string length * - * @return 0: The index is too large. - * Otherwise: The length of the index-th sequence - * (including the trailing '\0'). + * @return 0: the index is too large + * Otherwise: the length of the index-th sequence + * (including the trailing '\0') */ size_t ReStringList::sizeOf(Index index) const{ size_t rc = 0; @@ -152,11 +152,11 @@ size_t ReStringList::sizeOf(Index index) const{ } /** @brief Returns the length of the string given by an index. * - * @param index The index of the wanted string length. + * @param index the index of the wanted string length * - * @return 0: The index is too large. - * Otherwise: The length of the index-th sequence - * (excluding the trailing '\0'). + * @return 0: the index is too large.
+ * Otherwise: the length of the index-th sequence + * (excluding the trailing '\0') */ size_t ReStringList::strLengthOf(Index index) const{ size_t rc = 0; @@ -168,7 +168,7 @@ size_t ReStringList::strLengthOf(Index index) const{ } /** @brief Returns the sum of all string lengths stored in the array. * - * @return The sum of all string lengths stored in the array. + * @return the sum of all string lengths stored in the array */ size_t ReStringList::sumOfSizes() const{ size_t rc = 0; @@ -181,7 +181,7 @@ size_t ReStringList::sumOfSizes() const{ } /** @brief Returns the sum of all string lengths stored in the array. * - * @return The sum of all string lengths stored in the array. + * @return the sum of all string lengths stored in the array */ size_t ReStringList::sumOfStrLengths() const{ size_t rc = 0; @@ -194,12 +194,12 @@ size_t ReStringList::sumOfStrLengths() const{ } /** @brief Returns the index of a given string in the array. * - * @param toFind The string which will be searched. - * @param ignoreCase true: The search is case insensitive. - * false: The search is case sensitive. - * @param start The search starts at this index. + * @param toFind the string which will be searched + * @param ignoreCase true: the search is case insensitive. + * false: the search is case sensitive * - * @return -1: The string was not found. Otherwise: The index of the string. + * @return -1: the string was not found. Otherwise: the index of the string */ ReSeqArray::Index ReStringList::nextStartingWith(Index start, const char* prefix, bool ignoreCase){ @@ -247,11 +247,11 @@ ReSeqArray::Index ReStringList::nextStartingWith(Index start, } /** @brief Splits a string in an array. * - * @param list The string which is splitted. - * @param separator The separator of the substrings. - * If '\\n' a preceeding or trailing '\\r' will be ignored too. - * @param append false: The list will be cleared at the beginning. - * true: The new content is stored at the end. + * @param list the string which is splitted + * @param separator the separator of the substrings.
+ * If '\\n' a preceeding or trailing '\\r' will be ignored too + * @param append false: the list will be cleared at the beginning.
+ * true: the new content is stored at the end */ void ReStringList::split(const char* list, char separator, bool append){ if (! append) @@ -280,8 +280,8 @@ void ReStringList::split(const char* list, char separator, bool append){ } /** @brief Joins all string of the array into a string. * - * @param separator This string was put between the substrings. May be NULL or "". - * @param result Out: The result buffer. + * @param separator This string was put between the substrings. May be NULL or "" + * @param result Out: the result buffer * @return buffer (for chaining) */ ReByteBuffer& ReStringList::join(const char* separator, ReByteBuffer& result) const{ @@ -299,11 +299,11 @@ ReByteBuffer& ReStringList::join(const char* separator, ReByteBuffer& result) co } /** @brief Writes the stringlist to a file. * - * @param filename The name of the file. - * @param separator This string was put between the substrings. May be NULL. - * @param mode The file open mode: "w" for truncate and write, "a" for append. + * @param filename the name of the file + * @param separator this string was put between the substrings. May be NULL + * @param mode the file open mode: "w" for truncate and write, "a" for append * - * @return true: The file could be opened. false: otherwise. + * @return true: the file could be opened. false: otherwise */ bool ReStringList::writeToFile(const char* filename, const char* separator, const char* mode){ @@ -323,25 +323,25 @@ bool ReStringList::writeToFile(const char* filename, } /** @brief Reads a file into the array. * - * Every line is stored as entry of the array. + * Each line is stored as an element of the array. * - * @param filename The name of the file. - * @param cutNewline true: The newline characters will be cut. - * false: The newline characters will be stored. + * @param filename the name of the file + * @param cutNewline true: the newline characters will be cut
+ * false: the newline characters will be stored * - * @return true: The file could be opened. false: otherwise. + * @return true: the file could be opened. false: otherwise */ bool ReStringList::readFromFile(const char* filename, bool cutNewline){ FILE* fp = fopen(filename, "r"); bool rc = false; if (fp != NULL){ char line[8096]; - + char cc; while(fgets(line, sizeof line, fp) != NULL){ size_t length = strlen(line); if (cutNewline){ - while(--length > 0 && (line[length] == '\n' || line[length] == '\r')) - line[length] = '\n'; + while(length > 0 && ( (cc = line[length - 1]) == '\n' || cc == '\r')) + line[--length] = '\0'; } add(-1, line, length + 1); } @@ -351,11 +351,11 @@ bool ReStringList::readFromFile(const char* filename, bool cutNewline){ } /** @brief Returns the index of the first different string. * - * Compares the internal array of strings with another instance. + * Compares the internal array of strings with another instance * - * @param toCompare The other instance which will be compared. + * @param toCompare the other instance which will be compared * - * @return -1: The instances are equal. Otherwise: The index of the first different string. + * @return -1: the instances are equal. Otherwise: the index of the first different string * */ int ReStringList::firstDiff(const ReStringList& toCompare) const{ @@ -378,9 +378,9 @@ int ReStringList::firstDiff(const ReStringList& toCompare) const{ * Two instances are equal when the number of strings are equal * and the n.th string is equal to the n.th string in the other instance. * - * @param toCompare The other instance which will be compared. + * @param toCompare the other instance which will be compared * - * @return true: The other instance is equal. false: Otherwise. + * @return true: the other instance is equal. false: Otherwise */ bool ReStringList::equal(const ReStringList& toCompare) const{ bool rc = count() == toCompare.count() && firstDiff(toCompare) == -1; diff --git a/base/ReStringList.hpp b/base/ReStringList.hpp index 0020fbb..df96e71 100644 --- a/base/ReStringList.hpp +++ b/base/ReStringList.hpp @@ -10,7 +10,8 @@ /** * This class implements a dynamic array of C strings. - *

With this class it is very simple to break a string into a vector of substrings.

+ * With this class it is very simple to break a string into a vector of substrings. + * *
  * Example:
  * This example adds a column with a current number to a CSV file (comma separated file):
diff --git a/base/ReTestUnit.cpp b/base/ReTestUnit.cpp
index 366de0f..7b6a241 100644
--- a/base/ReTestUnit.cpp
+++ b/base/ReTestUnit.cpp
@@ -19,6 +19,7 @@ ReTestUnit::ReTestUnit(const char* name, const char* sourceFile)
 	m_buffer()
 {
 	logF(false, i18n("Start %s"), name);
+	createTestDir();
 }
 
 /** @brief Destructor.
@@ -165,11 +166,11 @@ void ReTestUnit::assertEqualFiles(const char* name1, const char* name2, int line
 	list1.readFromFile(name1);
 	list2.readFromFile(name2);
 	int ix = list1.firstDiff(list2);
-	if (ix < 0){
+	if (ix >= 0){
 		ReByteBuffer line1(list1.strOf(ix), list1.strLengthOf(ix));
 		int ixLine = line1.firstDifference(list2.strOf(ix), list2.strLengthOf(ix));
 		logF(true, i18n("%s-%d: Files differ in line %d-%d\n%s\n%s\n%s"),
-			m_sourceFile.str(), lineNo, ix, ixLine,
+			m_sourceFile.str(), lineNo, ix + 1, ixLine,
 			(int) list1.count() > ix ? list1.strOf(ix) : "",
 			(int) list2.count() > ix ? list2.strOf(ix) : "",
 			colMarker(ixLine));
@@ -177,6 +178,18 @@ void ReTestUnit::assertEqualFiles(const char* name1, const char* name2, int line
 
 }
 
+/** @brief Returns the full path of a file in the test directory.
+ *
+ * @param node		the node (filename without path)
+ * @param buffer	OUT: the filename will be constructed in this buffer
+ * @return 			buffer.str(): the full filename
+ */
+const char* ReTestUnit::buildFilename(const char* node, ReByteBuffer& buffer){
+	createTestDir();
+	buffer.setLength(0).append(m_tempDir).append(node);
+	return buffer.str();
+}
+
 /**
  * Returns a string usable as a marker of a given column.
  *
@@ -185,7 +198,7 @@ void ReTestUnit::assertEqualFiles(const char* name1, const char* name2, int line
  */
 const char* ReTestUnit::colMarker(int col){
 	if (col > 0)
-		m_buffer.setLengthAndFill(col - 1, '-');
+		m_buffer.fill('-', 0, col - 1);
 	else
 		m_buffer.setLength(0);
 	m_buffer.append("^", 1);
@@ -196,41 +209,81 @@ const char* ReTestUnit::colMarker(int col){
  * the name can be retrieved by getTestDir().
  */
 void ReTestUnit::createTestDir(){
-	char name[512];
-	if (getenv("TMP") != NULL){
-		strcpy(name, getenv("TMP"));
-	} else if (getenv("TEMP")){
-		strcpy(name, getenv("TEMP"));
-	} else {
-		strcpy(name, "/tmp/");
+	if (m_tempDir.length() == 0){
+		char name[512];
+		if (getenv("TMP") != NULL){
+			strcpy(name, getenv("TMP"));
+		} else if (getenv("TEMP")){
+			strcpy(name, getenv("TEMP"));
+		} else {
+			strcpy(name, "/tmp/");
+		}
+		char* ptr = name + strlen(name) - 1;
+		if (*ptr != ReStringUtils::pathSeparator())
+			strcpy(ptr + 1, ReStringUtils::pathSeparatorStr());
+		strcat(ptr, "retestunit");
+		strcat(ptr, ReStringUtils::pathSeparatorStr());
+		struct stat info;
+	#ifdef __WIN32__
+	#define ALLPERMS 0
+	#endif
+		if (lstat(name, &info) != 0)
+			_mkdir(name);
+		else{
+			char cmd[512 + 128];
+			_snprintf(cmd, sizeof cmd, "rm -Rf %s*", name);
+			system(cmd);
+		}
+		m_tempDir.set(name, -1);
 	}
-	char* ptr = name + strlen(name) - 1;
-	if (*ptr != ReStringUtils::pathSeparator())
-		strcpy(ptr + 1, ReStringUtils::pathSeparatorStr());
-	strcat(ptr, "retestunit");
-	strcat(ptr, ReStringUtils::pathSeparatorStr());
-	struct stat info;
-#ifdef __WIN32__
-#define lstat stat
-#define mkdir(name, flags) _mkdir(name)
-#define ALLPERMS 0
+}
+
+/**
+ * @brief Calculates the time since a given start.
+ *
+ * 
int64_t start = test.timer();
+ * ...
+ * int duration = test.milliSecSince(start);
+ * 
+ * + * @return a time usable for for runtime measurement + */ +int ReTestUnit::milliSecSince(int64_t start){ +#if defined __linux__ + int64_t diff = clock() - start; + return diff * 1000 / CLOCKS_PER_SEC; +#else +# error "timer not defined" +#endif +} + +/** + * @brief Returns a time value usable for runtime measurement. + * + * Note: The value is platform dependent. Use with milliSecSince(). + *
int64_t start = test.timer();
+ * ...
+ * int duration = test.milliSecSince(start);
+ * 
+ * @return a time usable for for runtime measurement + */ +int64_t ReTestUnit::timer(){ +#if defined __linux__ + return clock(); +#else +# error "timer not defined" #endif - if (lstat(name, &info) != 0) - _mkdir(name); - else{ - char cmd[512 + 128]; - _snprintf(cmd, sizeof cmd, "rm -Rf %s*", name); - system(cmd); - } - m_tempDir.set(name, -1); } + /** @brief Returns the temporary directory. * * @return the name of a temporary directory */ -const char* ReTestUnit::getTestDir(){ +const char* ReTestUnit::testDir(){ + createTestDir(); return m_tempDir.str(); } + /** @brief Creates a file and fills it with an given content. * * @param filename the name of the file diff --git a/base/ReTestUnit.hpp b/base/ReTestUnit.hpp index 2b1d187..d902ada 100644 --- a/base/ReTestUnit.hpp +++ b/base/ReTestUnit.hpp @@ -30,13 +30,17 @@ public: void assertNotNull(void* pointer, int lineNo); void assertNull(void* pointer, int lineNo); void assertTrue(bool conditon, int lineNo); + const char* buildFilename(const char* node, ReByteBuffer& buffer); void createDir(const char* filename); void createFile(const char* filename, const char* content); - void createTestDir(); const char* colMarker(int col); - const char* getTestDir(); + const char* testDir(); virtual bool log(bool isError, const char* message); virtual bool logF(bool isError, const char* format, ...); + int milliSecSince(int64_t start); + int64_t timer(); +private: + void createTestDir(); protected: int m_errorCount; ReByteBuffer m_name; diff --git a/base/ReVarArgs.cpp b/base/ReVarArgs.cpp index a0b9151..8f99580 100644 --- a/base/ReVarArgs.cpp +++ b/base/ReVarArgs.cpp @@ -213,7 +213,7 @@ ReVarArgs& ReVarArgs::arg(const char* value, int minWidth, int maxWidth, bool al store(value, maxWidth); } else { ReByteBuffer buffer; - buffer.setLengthAndFill(minWidth, ' '); + buffer.setLengthAndFillOut(minWidth, ' '); if (alignRight) memcpy(buffer.buffer() + minWidth - length, value, length); else diff --git a/base/rebase.hpp b/base/rebase.hpp index 19251d2..8ad33c6 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #if defined __linux__ @@ -26,7 +27,8 @@ # include # include # include - +# include +typedef u_int64_t uint64_t; # define _strdup strdup # define _unlink unlink # define _strnicmp(s1, s2, n) strncasecmp(s1, s2, n) @@ -38,6 +40,7 @@ # include # include # define _memcmp(t,s,n) memcmp(t,s,n) +# define lstat stat typedef _int64 int64_t; typedef unsigned long long uint64_t; typedef unsigned char uint8_t; diff --git a/cunit/cuReByteBuffer.cpp b/cunit/cuReByteBuffer.cpp index a97af5f..41481bd 100644 --- a/cunit/cuReByteBuffer.cpp +++ b/cunit/cuReByteBuffer.cpp @@ -2,7 +2,6 @@ * cuReByteBuffer.cpp * * Created on: 27.11.2010 - * Author: wk */ #include "base/rebase.hpp" class TestReByteBuffer : public ReTestUnit { @@ -13,6 +12,8 @@ public: } private: void run(){ + testFill(); + testAppendMilliSec(); testSetDelta(); testFirstDiff(); testCount(); @@ -32,6 +33,21 @@ private: testSplice(); testReplace(); } + void testFill(){ + ReByteBuffer buf; + buf.fill('=', 0, 3); + checkEqu("===", buf.str()); + buf.fill('x', 1, 2); + checkEqu("=x=", buf.str()); + } + void testAppendMilliSec(){ + ReByteBuffer buf; + checkEqu("5.123", buf.appendMilliSec(5123).str()); + checkEqu("32:45.789", buf.setLength(0) + .appendMilliSec(32*60*1000+45789).str()); + checkEqu("17:04:06.976", buf.setLength(0) + .appendMilliSec(17*3600*1000 + 4*60*1000 + 6976).str()); + } void testSetDelta(){ ReByteBuffer buf("abcd"); int maxDelta = 512 * (1 << 10); @@ -220,15 +236,15 @@ private: checkEqu("123ab", buffer.buffer()); checkEqu(5u, buffer.length()); - buffer.setLengthAndFill(8, 'x'); + buffer.setLengthAndFillOut(8, 'x'); checkEqu("123abxxx", buffer.buffer()); checkEqu(8u, buffer.length()); buffer.setLength(3); checkEqu("123", buffer.buffer()); checkEqu(3u, buffer.length()); - buffer.setLengthAndFill(511, 'y'); - buffer.setLengthAndFill(512, 'z'); + buffer.setLengthAndFillOut(511, 'y'); + buffer.setLengthAndFillOut(512, 'z'); checkEqu("yyz", buffer.buffer() + 509); checkEqu(521u, buffer.capacity()); @@ -339,7 +355,7 @@ private: checkEqu("01234", buf1.str()); checkEqu(5u, buf1.length()); - buf1.setLengthAndFill(8, 'X'); + buf1.setLengthAndFillOut(8, 'X'); checkEqu("01234XXX", buf1.str()); checkEqu(8u, buf1.length()); checkEqu(2000u, buf1.capacity()); diff --git a/cunit/cuReDirectory.cpp b/cunit/cuReDirectory.cpp index 566e4e5..473e259 100644 --- a/cunit/cuReDirectory.cpp +++ b/cunit/cuReDirectory.cpp @@ -7,9 +7,8 @@ public: } private: void run(){ - createTestDir(); ReByteBuffer dir; - dir.set(getTestDir(), -1); + dir.set(testDir(), -1); ReByteBuffer file1 = dir; file1.append("abc.1.txt", -1); createFile(file1.str(), "abc1"); diff --git a/cunit/cuHashList.cpp b/cunit/cuReHashList.cpp similarity index 96% rename from cunit/cuHashList.cpp rename to cunit/cuReHashList.cpp index cd92cd5..3df7c16 100644 --- a/cunit/cuHashList.cpp +++ b/cunit/cuReHashList.cpp @@ -1,4 +1,5 @@ #include "base/rebase.hpp" +#include "math/remath.hpp" class TestReHashList : public ReTestUnit { public: @@ -11,6 +12,7 @@ private: testNext(); } void massTest(){ + ReCongruentialGenerator rand; ReHashList hash(); ReByteBuffer key, value; log(false, "missing masstest"); diff --git a/cunit/cuReProgramArgs.cpp b/cunit/cuReProgramArgs.cpp index 4681084..075cc32 100644 --- a/cunit/cuReProgramArgs.cpp +++ b/cunit/cuReProgramArgs.cpp @@ -25,6 +25,36 @@ private: } catch (ReOptionException& exc) { checkEqu("Unknown option: v", exc.getMessage()); } + } + void createExpectedShortHelp(const char* filename){ + createFile(filename, +"test This tests the usage of ReProgramArg\n" +"This tests the usage of ReProgramArg\n" +"\n" +":\n" +"-B or --boolval2\n" +" This is the 2nd boolean arg\n" +"-x or --boolval3\n" +" This is the 3rd boolean arg\n" +"-Y or --boolval4\n" +" This is the 4th boolean arg\n" +"-S[] or --estring=[] Default value: empty\n" +" This string may be empty\n" +"-U[] or --estring2=[] Default value: undef2\n" +" This 2nd string may be empty\n" +"-i or --intval= Default value: 9\n" +" This is an integer arg\n" +"-I or --intval= Default value: 1000\n" +" This is the 2nd integer arg\n" +"-s or --string= Default value: 'abc'\n" +" This string must be non empty\n" +"-u or --string2= Default value: 'undef'\n" +" This 2nd string must be non empty\n" +"Example(s):\n" +"$0 -b+ -B- file dir\ttest of an exampl+++ Not really an error!\n" +"\ttest of an exampl+++ Not really an error!\n" +"+++ Not really an error!\n" + ); } void testShort(){ ReProgramArgs args("test \nThis tests the usage of ReProgramArgs", @@ -67,8 +97,17 @@ private: checkEqu("arg1", args.getArg(0)); checkEqu("arg2", args.getArg(1)); checkEqu(2, args.getArgCount()); - - args.help("Not really an error!", false, stdout); + ReByteBuffer fn; + FILE* fp = fopen(buildFilename("help.tmp.txt", fn), "w"); + checkF(fp == NULL); + if (fp != NULL){ + args.help("Not really an error!", false, fp); + fclose(fp); + ReByteBuffer fnExpected; + buildFilename("help.exp.txt", fnExpected); + createExpectedShortHelp(fnExpected.str()); + checkFileEqu(fnExpected.str(), fn.str()); + } } void testSetUsage(){ class MyArgs : public ReProgramArgs { @@ -82,6 +121,32 @@ private: args.setUsage(usage); checkEqu("x1", args.usage().strOf(0)); checkEqu("x2", args.usage().strOf(1)); + } + void createExpectedLongHelp(const char* filename){ + createFile(filename, +"test :\n" +"--boolval2\n" +" This is the 2nd boolean arg\n" +"-x or --boolval3\n" +" This is the 3rd boolean arg\n" +"--boolval4\n" +" This is the 3rd boolean arg\n" +"--estring=[] Default value: empty\n" +" This string may be empty\n" +"-U[] or --estring2=[] Default value: undef2\n" +" This 2nd string may be empty\n" +"-V[] or --estring3=[] Default value: undef3\n" +" This 3thrd string may be empty\n" +"-i or --intval= Default value: 9\n" +" This is an integer arg\n" +"-s or --string= Default value: 'abc'\n" +" This string must be non empty\n" +"Example(s):\n" +"test -intval=10 --boolval=t\n" + ); } void testLong(){ const char* call[] = { @@ -125,7 +190,16 @@ private: checkEqu("arg1", args.getArg(0)); checkEqu("arg2", args.getArg(1)); checkEqu(2, args.getArgCount()); - args.help(NULL, false, stdout); + ReByteBuffer fn; + FILE* fp = fopen(buildFilename("help.tmp.txt", fn), "w"); + checkT(fp != NULL); + if (fp){ + args.help(NULL, false, fp); + fclose(fp); + ReByteBuffer fnExpected; + createExpectedLongHelp(buildFilename("help.exp.txt", fnExpected)); + checkFileEqu(fnExpected.str(), fn.str()); + } } }; extern void testReProgramArgs(void); diff --git a/cunit/cuReRandomizer.cpp b/cunit/cuReRandomizer.cpp new file mode 100644 index 0000000..7d2285c --- /dev/null +++ b/cunit/cuReRandomizer.cpp @@ -0,0 +1,49 @@ +#include "base/rebase.hpp" +#include "math/remath.hpp" + +class TestReRandomizer : public ReTestUnit { +public: + TestReRandomizer() : + ReTestUnit("ReRandomizer", __FILE__) + { + run(); + } +private: + void run(){ + testNextInt64Repeater(); + testNextInt64(); + + } + void testNextInt64Repeater(){ + ReCongruentialGenerator rand; + const int MAX = 16; + time_t start = time(NULL); + ReRandomizer::seed_t field[MAX]; + for (int ix = 0; ix < MAX; ix++) + field[ix] = rand.nextInt64(); + rand.reset(); + for (int ix = 0; ix < MAX; ix++){ + checkEqu(field[ix], rand.nextInt64(ix + 10)); + } + } + void testNextInt64(){ + ReCongruentialGenerator rand; + const int MAX = 16; + time_t start = time(NULL); + ReRandomizer::seed_t field[MAX]; + for (int ix = 0; ix < MAX; ix++) + field[ix] = rand.nextInt64(ix + 10); + rand.reset(); + for (int ix = 0; ix < MAX; ix++){ + checkEqu(field[ix], rand.nextInt64(ix + 10)); + checkT(field[ix] >= 0 && field[ix] < ix + 10); + } + time_t diff = time(NULL) - start; + } +}; +extern void testReRandomizer(void); + +void testReRandomizer(void){ + TestReRandomizer unit; +} + diff --git a/cunit/cuReStringList.cpp b/cunit/cuReStringList.cpp index a4baf00..9da0d4d 100644 --- a/cunit/cuReStringList.cpp +++ b/cunit/cuReStringList.cpp @@ -148,9 +148,8 @@ private: } void testFile(){ if (true){ - createTestDir(); ReByteBuffer file; - file.set(getTestDir(), -1).append("abc.csv", -1); + buildFilename("abc.csv", file); ReStringList list; const char* str = "1;abc;xyz;4;;99"; @@ -159,6 +158,20 @@ private: ReStringList list2; list2.readFromFile(file.str(), true); + checkEqu("1", list2.strOf(0)); + checkEqu("abc", list2.strOf(1)); + checkEqu("xyz", list2.strOf(2)); + checkEqu("4", list2.strOf(3)); + checkEqu("", list2.strOf(4)); + checkEqu("99", list2.strOf(5)); + list2.clear(); + list2.readFromFile(file.str(), false); + checkEqu("1", list2.strOf(0)); + checkEqu("abc", list2.strOf(1)); + checkEqu("xyz", list2.strOf(2)); + checkEqu("4", list2.strOf(3)); + checkEqu("", list2.strOf(4)); + checkEqu("99", list2.strOf(5)); checkEqu(-1, list2.firstDiff(list2)); } diff --git a/cunit/cuReTest.cpp b/cunit/cuReTest.cpp index 2f7766b..15bec42 100644 --- a/cunit/cuReTest.cpp +++ b/cunit/cuReTest.cpp @@ -7,10 +7,29 @@ public: } private: void run(){ + testFileNameInTestDir(); + testTimer(); testBasic(); testColMarker(); testEquFiles(); } + void testFileNameInTestDir(){ + ReByteBuffer fn; + const char* name = buildFilename("xyz.txt", fn); + checkEqu(name, fn.str()); + checkT(fn.endsWith("xyz.txt")); + checkT(fn.startsWith(testDir())); + } + void testTimer(){ + int64_t start = timer(); + // busy wait (clock() measures only busy times): + time_t to = time(NULL) + 1; + while(time(NULL) <= to){ + // do nothing + } + int duration = milliSecSince(start); + checkT(duration >= 1000 && duration < 3000); + } void testBasic(){ checkT(true); checkF(false); @@ -36,16 +55,14 @@ private: log(false, "end of 8 expected errors"); } void testColMarker(){ - checkEqu("--^", colMarker(2)); + checkEqu("-^", colMarker(2)); checkEqu("^", colMarker(0)); } void testEquFiles(){ - createTestDir(); - ReByteBuffer dir = getTestDir(); - ReByteBuffer fn1(dir); - fn1.append("x1.txt"); - ReByteBuffer fn2(dir); - fn2.append("x2.txt"); + ReByteBuffer fn1; + buildFilename("x1.txt", fn1); + ReByteBuffer fn2; + buildFilename("x2.txt", fn2); createFile(fn1.str(), "123\nline 2"); createFile(fn2.str(), "123\nline 2"); checkFileEqu(fn1.str(), fn2.str()); diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp index 9314d9f..f64406f 100644 --- a/cunit/cuReTraverser.cpp +++ b/cunit/cuReTraverser.cpp @@ -13,8 +13,7 @@ static const char* s_empty[] = { NULL }; class TestReTraverser : public ReTestUnit { public: TestReTraverser() : ReTestUnit("ReTraverser", __FILE__){ - createTestDir(); - m_base = getTestDir(); + m_base = testDir(); m_base.append("traverser").append(ReTraverser::m_separatorStr, -1); _mkdir(m_base.str()); run(); @@ -70,7 +69,7 @@ private: void testCopyFile(){ ReByteBuffer src(m_base); src.append("dir1/dir1_2/dir1_2_1/x1.txt"); - ReByteBuffer trg(getTestDir()); + ReByteBuffer trg(testDir()); trg.append("copy_x1.txt"); ReByteBuffer buffer; buffer.ensureSize(5); diff --git a/cunit/cuReconfig.cpp b/cunit/cuReconfig.cpp index 94c22cd..4ee2885 100644 --- a/cunit/cuReconfig.cpp +++ b/cunit/cuReconfig.cpp @@ -11,9 +11,8 @@ private: testBasic(); } void testBasic(){ - createTestDir(); ReByteBuffer fn; - fn.append(getTestDir(), -1).append("reconfigfile.cfg", -1); + buildFilename("reconfigfile.cfg", fn); createFile(fn.str(), "#x.int=a\nx.int=1\nx.bool=true\nx.str=abc\nx.bool2=0\nstring=abc\n"); ReConfigFile config(fn.str()); checkT(config.isValid()); diff --git a/cunit/testall.cpp b/cunit/testall.cpp index 7ce041e..961541a 100644 --- a/cunit/testall.cpp +++ b/cunit/testall.cpp @@ -11,9 +11,6 @@ #endif void testBase(){ - extern void testReLogger(void); - testReLogger(); - testReLogger(); extern void testReTestUnit(); testReTestUnit(); @@ -58,13 +55,18 @@ void testString(){ } void testOs(){ void testReTraverser(); - testReTraverser(); + //testReTraverser(); +} +void testMath(){ + extern void testReRandomizer(); + testReRandomizer(); } void testAll(){ try { - testOs(); testBase(); + testMath(); + testOs(); testString(); } catch (ReException e){ fprintf(stderr, "testBase.cpp: unexpected exception: %s\n", e.getMessage()); diff --git a/math/ReRandomizer.cpp b/math/ReRandomizer.cpp index 552b750..233c500 100644 --- a/math/ReRandomizer.cpp +++ b/math/ReRandomizer.cpp @@ -5,17 +5,16 @@ * Author: wk */ -#include "assert.h" -#include "memory.h" -#include "limits.h" -#include "math.h" -#include "remath.hpp" + +#include "base/rebase.hpp" +#include "math/remath.hpp" static bool s_trace = false; /** * @brief Constructor. */ -ReRandomizer::ReRandomizer(){ +ReRandomizer::ReRandomizer() +{ } /** * @brief Destructor. @@ -38,16 +37,69 @@ char ReRandomizer::nextChar() return rc; } +/** + * @brief Returns a random number which is not predictable. + * + * @return a number which is not predictable + */ +ReRandomizer::seed_t ReRandomizer::nearTrueRandom(){ + time_t random = time(NULL); + static int dummy = 5; + void* dummy2 = malloc(1); + free(dummy2); + seed_t rc = (((seed_t) random) << 31) + ((seed_t) &dummy << 9) + (-random ^ 0x20111958) + ^ (seed_t(dummy2)); +#if defined __linux__ + int fh = open("/dev/urandom", O_RDONLY); + char buffer[sizeof (seed_t)]; + size_t length = 0; + + if (read(fh, buffer, sizeof buffer) > 0) + rc ^= *(seed_t*) buffer; + close(fh); +#else +#error "no true random" +#endif +} /** * @brief Returns the next random integer. * * + * @param maxValue The maximum of the result (including). * @param minValue The minimum of the result. + * + * @return The next seed. + */ +int ReRandomizer::nextInt(int maxValue, int minValue){ + int rc; + if (minValue > maxValue){ + rc = minValue; + minValue = maxValue; + maxValue = rc; + } + seed_t seed = nextSeed(); + if (minValue == maxValue) + rc = minValue; + else + // we calculate in 64 bit: + rc = (int) (minValue + seed % (maxValue - minValue + 1)); + if (s_trace){ + static int count = 0; + printf ("%c %8x ", count++ % 4 == 0 ? '\n' : ' ', rc); + } + return rc; +} + +/** + * @brief Returns the next random integer. + * + * * @param maxValue The maximum of the result (including). + * @param minValue The minimum of the result. * * @return The next seed. */ -int ReRandomizer::nextInt(int minValue, int maxValue){ +int64_t ReRandomizer::nextInt64(int64_t maxValue, int64_t minValue){ int rc; if (minValue > maxValue){ rc = minValue; @@ -57,17 +109,19 @@ int ReRandomizer::nextInt(int minValue, int maxValue){ seed_t seed = nextSeed(); if (minValue == maxValue) rc = minValue; - else if (minValue == 0 && maxValue == INT_MAX) + else if (minValue == 0 && maxValue == LLONG_MAX) rc = abs(seed); - else if (unsigned(maxValue - minValue) < INT_MAX) + else if (uint64_t(maxValue - minValue) < LLONG_MAX) + // no signed int64 overflow: rc = minValue + seed % (maxValue - minValue + 1); else { + // int64 overflow: we need a higher precision: double rc2 = minValue + fmod((double) seed, maxValue - minValue); rc = (int) rc2; } if (s_trace){ static int count = 0; - printf ("%c %8x ", count++ % 4 == 0 ? '\n' : ' ', rc); + printf ("%c %16llx ", count++ % 4 == 0 ? '\n' : ' ', rc); } return rc; } @@ -101,6 +155,7 @@ char* ReRandomizer::nextString(char* buffer, int maxLength, int minLength){ buffer[len] = '\0'; return buffer; } + /** * @brief Builds a random permutation of an array. * @@ -162,7 +217,8 @@ void ReRandomizer::shuffle(void* array, size_t length, size_t elemSize){ ReCongruentialGenerator::ReCongruentialGenerator() : m_seed(0x4711), m_factor(2631), - m_increment(0x9) + m_increment(0x9), + m_lastSetSeed(0x4711) { } /** @@ -176,7 +232,7 @@ ReCongruentialGenerator::~ReCongruentialGenerator(){ * * @return The current factor. */ -ReRandomizer::seed_t ReCongruentialGenerator::getFactor() const +ReRandomizer::seed_t ReCongruentialGenerator::factor() const { return m_factor; } @@ -186,7 +242,7 @@ ReRandomizer::seed_t ReCongruentialGenerator::getFactor() const * * @return The current increment. */ -ReRandomizer::seed_t ReCongruentialGenerator::getIncrement() const +ReRandomizer::seed_t ReCongruentialGenerator::increment() const { return m_increment; } @@ -196,11 +252,20 @@ ReRandomizer::seed_t ReCongruentialGenerator::getIncrement() const * * @return The current seed. */ -ReRandomizer::seed_t ReCongruentialGenerator::getSeed() const +ReRandomizer::seed_t ReCongruentialGenerator::seed() const { return m_seed; } +/** + * @brief Sets the seed to the value given by the last setSeed(). + * + * Note: The constructor does the first setSeed(). + */ +void ReCongruentialGenerator::reset(){ + m_seed = m_lastSetSeed; +} + /** * Sets the factor. * @@ -227,8 +292,8 @@ void ReCongruentialGenerator::setIncrement(seed_t increment) */ void ReCongruentialGenerator::setSeed(seed_t seed) { - this->m_seed = seed; + m_seed = m_lastSetSeed = seed; if (s_trace) - printf(" Seed: %x ", seed); + printf(" Seed: %llx ", seed); } diff --git a/math/ReRandomizer.hpp b/math/ReRandomizer.hpp index 958649b..32f0812 100644 --- a/math/ReRandomizer.hpp +++ b/math/ReRandomizer.hpp @@ -7,44 +7,53 @@ #ifndef RANDOMIZER_H_ #define RANDOMIZER_H_ -#include "stdio.h" -#include "limits.h" /** * This implements an abstract base class for random generators. */ class ReRandomizer { public: - enum { CHARRANGE = 128 - ' ' }; - typedef unsigned int seed_t; + enum { START_RANGE = ' ', + CHARRANGE = 128 - START_RANGE }; + typedef uint64_t seed_t; public: ReRandomizer(); virtual ~ReRandomizer(); public: - virtual int nextInt(int minValue = 0, int maxValue = INT_MAX); - void shuffle(void* array, size_t length, size_t elemSize); + virtual int nextInt(int maxValue = INT_MAX, int minValue = 0); + virtual int64_t nextInt64(int64_t maxValue = LLONG_MAX, int64_t minValue = 0); char nextChar(); char* nextString(char* buffer, int maxLength = 80, int minLength = 0); + void shuffle(void* array, size_t length, size_t elemSize); + /** @brief Sets the instance to a defined start state. + */ + virtual void reset() = 0; protected: + /** @brief Returns the next pseudo random number. + * @return the next pseudo random number + * */ virtual seed_t nextSeed() = 0; +public: + seed_t nearTrueRandom(); }; /** * Implements a simple random generator. * A linear congruential generator produces the next value using this formula: * seed = (seed * factor + increment) % modulus - * In this implementation modulus is 2**32. + * In this implementation modulus is 2**64. */ class ReCongruentialGenerator : public ReRandomizer { public: ReCongruentialGenerator(); virtual ~ReCongruentialGenerator(); public: - seed_t getFactor() const; - seed_t getIncrement() const; + seed_t factor() const; + seed_t increment() const; + seed_t seed() const; + virtual void reset(); void setFactor(seed_t factor); void setIncrement(seed_t increment); - seed_t getSeed() const; void setSeed(seed_t m_seed); private: virtual seed_t nextSeed(); @@ -52,6 +61,7 @@ private: seed_t m_seed; seed_t m_factor; seed_t m_increment; + seed_t m_lastSetSeed; }; #endif /* RANDOMIZER_H_ */ diff --git a/math/remath.hpp b/math/remath.hpp index d3b64bc..d9233c3 100644 --- a/math/remath.hpp +++ b/math/remath.hpp @@ -7,8 +7,9 @@ #ifndef REMATH_HPP_ #define REMATH_HPP_ +#include "math.h" -#include "ReObfuscator.hpp" -#include "ReRandomizer.hpp" +#include "math/ReObfuscator.hpp" +#include "math/ReRandomizer.hpp" #endif /* REMATH_HPP_ */ -- 2.39.5