Add BufferSearch (from arch-repo-manager) to use it in syncthingtray as well
This commit is contained in:
parent
db87472be9
commit
6558ff487a
|
@ -21,6 +21,7 @@ set(HEADER_FILES
|
|||
io/binaryreader.h
|
||||
io/binarywriter.h
|
||||
io/bitreader.h
|
||||
io/buffersearch.h
|
||||
io/copy.h
|
||||
io/inifile.h
|
||||
io/path.h
|
||||
|
@ -49,6 +50,7 @@ set(SRC_FILES
|
|||
io/binaryreader.cpp
|
||||
io/binarywriter.cpp
|
||||
io/bitreader.cpp
|
||||
io/buffersearch.cpp
|
||||
io/inifile.cpp
|
||||
io/path.cpp
|
||||
io/nativefilestream.cpp
|
||||
|
@ -112,8 +114,8 @@ set(META_APP_AUTHOR "Martchus")
|
|||
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
||||
set(META_APP_DESCRIPTION "Useful C++ classes and routines such as argument parser, IO and conversion utilities")
|
||||
set(META_VERSION_MAJOR 5)
|
||||
set(META_VERSION_MINOR 10)
|
||||
set(META_VERSION_PATCH 6)
|
||||
set(META_VERSION_MINOR 11)
|
||||
set(META_VERSION_PATCH 0)
|
||||
|
||||
# find required 3rd party libraries
|
||||
include(3rdParty)
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
#include "./buffersearch.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace CppUtilities {
|
||||
|
||||
/*!
|
||||
* \class BufferSearch
|
||||
* \brief The BufferSearch struct invokes a callback if an initially given search term occurs in consecutively provided buffers.
|
||||
* \remarks
|
||||
* - The class works without making internal copies of the specified buffers, except for the search result.
|
||||
* - The callback is invoked after the search term has been found and one of the specified termination characters occurred. The
|
||||
* search result is passed to the callback.
|
||||
* - The "search result" is the data after the last character of the search term and before any of the specified termination
|
||||
* characters.
|
||||
* - If no termination characters are specified, the callback is invoked directly after the search term occurred (with an empty
|
||||
* search result).
|
||||
* - If the specified give-up term has occurred, operator() will exit early and the specified callback will not be invoked
|
||||
* anymore.
|
||||
* - If the callback has been invoked, operator() will exit early and the callback will not be invoked anymore (even if the
|
||||
* search term occurs again). Call reset() after consuming the result within the callback to continue the search.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Processes the specified \a buffer. Invokes the callback according to the remarks mentioned in the class documentation.
|
||||
*/
|
||||
void BufferSearch::operator()(const char *buffer, std::size_t bufferSize)
|
||||
{
|
||||
if (m_hasResult || (!m_giveUpTerm.empty() && m_giveUpTermIterator == m_giveUpTerm.end())) {
|
||||
return;
|
||||
}
|
||||
for (auto i = buffer, end = buffer + bufferSize; i != end; ++i) {
|
||||
const auto currentChar = *i;
|
||||
if (m_searchTermIterator == m_searchTerm.end()) {
|
||||
if (m_terminationChars.empty()) {
|
||||
m_hasResult = true;
|
||||
} else {
|
||||
for (const auto &terminationChar : m_terminationChars) {
|
||||
if (currentChar == terminationChar) {
|
||||
m_hasResult = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_hasResult) {
|
||||
m_callback(*this, std::move(m_result));
|
||||
return;
|
||||
}
|
||||
m_result += currentChar;
|
||||
continue;
|
||||
}
|
||||
if (currentChar == *m_searchTermIterator) {
|
||||
++m_searchTermIterator;
|
||||
} else {
|
||||
m_searchTermIterator = m_searchTerm.begin();
|
||||
}
|
||||
if (m_giveUpTerm.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (currentChar == *m_giveUpTermIterator) {
|
||||
++m_giveUpTermIterator;
|
||||
} else {
|
||||
m_giveUpTermIterator = m_giveUpTerm.begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the search to its initial state (assuming no characters of the search term or give-up term have been found yet).
|
||||
*/
|
||||
void BufferSearch::reset()
|
||||
{
|
||||
m_searchTermIterator = m_searchTerm.begin();
|
||||
m_giveUpTermIterator = m_giveUpTerm.begin();
|
||||
m_terminationTermIterator = m_terminationTerm.begin();
|
||||
m_hasResult = false;
|
||||
m_result.clear();
|
||||
}
|
||||
|
||||
} // namespace CppUtilities
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef IOUTILITIES_BUFFER_SEARCH_H
|
||||
#define IOUTILITIES_BUFFER_SEARCH_H
|
||||
|
||||
#include "../global.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace CppUtilities {
|
||||
|
||||
class CPP_UTILITIES_EXPORT BufferSearch {
|
||||
public:
|
||||
using CallbackType = std::function<void(BufferSearch &, std::string &&)>;
|
||||
BufferSearch(std::string_view searchTerm, std::string_view terminationChars, std::string_view giveUpTerm, CallbackType &&callback);
|
||||
void operator()(std::string_view buffer);
|
||||
void operator()(const char *buffer, std::size_t bufferSize);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
const std::string_view m_searchTerm;
|
||||
const std::string_view m_terminationChars;
|
||||
const std::string_view m_terminationTerm;
|
||||
const std::string_view m_giveUpTerm;
|
||||
const CallbackType m_callback;
|
||||
std::string_view::const_iterator m_searchTermIterator;
|
||||
std::string_view::const_iterator m_giveUpTermIterator;
|
||||
std::string_view::const_iterator m_terminationTermIterator;
|
||||
std::string m_result;
|
||||
bool m_hasResult;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new BufferSearch. Might be overloaded in the future.
|
||||
*/
|
||||
inline BufferSearch::BufferSearch(
|
||||
std::string_view searchTerm, std::string_view terminationChars, std::string_view giveUpTerm, CallbackType &&callback)
|
||||
: m_searchTerm(searchTerm)
|
||||
, m_terminationChars(terminationChars)
|
||||
, m_giveUpTerm(giveUpTerm)
|
||||
, m_callback(std::move(callback))
|
||||
, m_searchTermIterator(m_searchTerm.begin())
|
||||
, m_giveUpTermIterator(m_giveUpTerm.begin())
|
||||
, m_terminationTermIterator(m_terminationTerm.begin())
|
||||
, m_hasResult(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Processes the specified \a buffer. Invokes the callback according to the remarks mentioned in the class documentation.
|
||||
*/
|
||||
inline void BufferSearch::operator()(std::string_view buffer)
|
||||
{
|
||||
(*this)(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
} // namespace CppUtilities
|
||||
|
||||
#endif // IOUTILITIES_BUFFER_SEARCH_H
|
|
@ -7,6 +7,7 @@
|
|||
#include "../io/binaryreader.h"
|
||||
#include "../io/binarywriter.h"
|
||||
#include "../io/bitreader.h"
|
||||
#include "../io/buffersearch.h"
|
||||
#include "../io/copy.h"
|
||||
#include "../io/inifile.h"
|
||||
#include "../io/misc.h"
|
||||
|
@ -43,6 +44,7 @@ class IoTests : public TestFixture {
|
|||
CPPUNIT_TEST(testBinaryReader);
|
||||
CPPUNIT_TEST(testBinaryWriter);
|
||||
CPPUNIT_TEST(testBitReader);
|
||||
CPPUNIT_TEST(testBufferSearch);
|
||||
CPPUNIT_TEST(testPathUtilities);
|
||||
CPPUNIT_TEST(testIniFile);
|
||||
CPPUNIT_TEST(testAdvancedIniFile);
|
||||
|
@ -62,6 +64,7 @@ public:
|
|||
void testBinaryReader();
|
||||
void testBinaryWriter();
|
||||
void testBitReader();
|
||||
void testBufferSearch();
|
||||
void testPathUtilities();
|
||||
void testIniFile();
|
||||
void testAdvancedIniFile();
|
||||
|
@ -233,7 +236,7 @@ void IoTests::testBinaryWriter()
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Tests the BitReader.
|
||||
* \brief Tests the BitReader class.
|
||||
*/
|
||||
void IoTests::testBitReader()
|
||||
{
|
||||
|
@ -259,6 +262,40 @@ void IoTests::testBitReader()
|
|||
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8 * sizeof(testData)), reader.bitsAvailable());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Tests the BufferSearch class.
|
||||
*/
|
||||
void IoTests::testBufferSearch()
|
||||
{
|
||||
// setup search to test
|
||||
auto expectedResult = std::string();
|
||||
auto hasResult = false;
|
||||
auto bs = BufferSearch("Updated version: ", "\e\n", "Starting build", [&](BufferSearch &, std::string &&result) {
|
||||
CPPUNIT_ASSERT_EQUAL(expectedResult, result);
|
||||
CPPUNIT_ASSERT_MESSAGE("callback only invoked once", !hasResult);
|
||||
hasResult = true;
|
||||
});
|
||||
|
||||
// feed data into the search
|
||||
char buffer[30];
|
||||
bs(buffer, 0);
|
||||
CPPUNIT_ASSERT(!hasResult);
|
||||
std::strcpy(buffer, "Starting Updated");
|
||||
bs(std::string_view(buffer, 16));
|
||||
CPPUNIT_ASSERT(!hasResult);
|
||||
std::strcpy(buffer, " version: some ");
|
||||
bs(buffer, 15);
|
||||
CPPUNIT_ASSERT(!hasResult);
|
||||
expectedResult = "some version number";
|
||||
std::strcpy(buffer, "version number\emore chars");
|
||||
bs(buffer, 25);
|
||||
CPPUNIT_ASSERT(hasResult);
|
||||
hasResult = false;
|
||||
std::strcpy(buffer, "... Starting build ...");
|
||||
bs(buffer, 22);
|
||||
CPPUNIT_ASSERT(!hasResult);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Tests fileName() and removeInvalidChars().
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue