mirror of
https://github.com/pocoproject/poco.git
synced 2025-03-30 07:26:33 +02:00
add visitor pattern implementation for Poco::Dynamic::Var (#4144)
* add visitor pattern implementation for Poco::Dynamic::Var * add changes to Makefile and vcxproj for VarVisitor * resolve review comments Poco::Dynamic::Var --------- Co-authored-by: Alexander B <bas524@ya.ru>
This commit is contained in:
parent
a9f889f5cf
commit
6a5387ec21
@ -1463,6 +1463,7 @@
|
||||
<ClCompile Include="src\Var.cpp" />
|
||||
<ClCompile Include="src\VarHolder.cpp" />
|
||||
<ClCompile Include="src\VarIterator.cpp" />
|
||||
<ClCompile Include="src\VarVisitor.cpp" />
|
||||
<ClCompile Include="src\Void.cpp" />
|
||||
<ClCompile Include="src\Windows1250Encoding.cpp" />
|
||||
<ClCompile Include="src\Windows1251Encoding.cpp" />
|
||||
@ -1843,4 +1844,4 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -1463,6 +1463,7 @@
|
||||
<ClCompile Include="src\Var.cpp" />
|
||||
<ClCompile Include="src\VarHolder.cpp" />
|
||||
<ClCompile Include="src\VarIterator.cpp" />
|
||||
<ClCompile Include="src\VarVisitor.cpp" />
|
||||
<ClCompile Include="src\Void.cpp" />
|
||||
<ClCompile Include="src\Windows1250Encoding.cpp" />
|
||||
<ClCompile Include="src\Windows1251Encoding.cpp" />
|
||||
@ -1843,4 +1844,4 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -1469,6 +1469,7 @@
|
||||
<ClCompile Include="src\Var.cpp" />
|
||||
<ClCompile Include="src\VarHolder.cpp" />
|
||||
<ClCompile Include="src\VarIterator.cpp" />
|
||||
<ClCompile Include="src\VarVisitor.cpp" />
|
||||
<ClCompile Include="src\Void.cpp" />
|
||||
<ClCompile Include="src\Windows1250Encoding.cpp" />
|
||||
<ClCompile Include="src\Windows1251Encoding.cpp" />
|
||||
@ -1849,4 +1850,4 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -2052,6 +2052,7 @@
|
||||
<ClCompile Include="src\Var.cpp" />
|
||||
<ClCompile Include="src\VarHolder.cpp" />
|
||||
<ClCompile Include="src\VarIterator.cpp" />
|
||||
<ClCompile Include="src\VarVisitor.cpp" />
|
||||
<ClCompile Include="src\Void.cpp" />
|
||||
<ClCompile Include="src\Windows1250Encoding.cpp" />
|
||||
<ClCompile Include="src\Windows1251Encoding.cpp" />
|
||||
@ -2456,4 +2457,4 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -29,7 +29,7 @@ objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel \
|
||||
ThreadPool ThreadTarget ActiveDispatcher Timer Timespan Timestamp Timezone Token URI \
|
||||
FileStreamFactory URIStreamFactory URIStreamOpener UTF32Encoding UTF16Encoding UTF8Encoding UTF8String \
|
||||
Unicode UnicodeConverter Windows1250Encoding Windows1251Encoding Windows1252Encoding \
|
||||
UUID UUIDGenerator Void Var VarHolder VarIterator Format Pipe PipeImpl PipeStream SharedMemory \
|
||||
UUID UUIDGenerator Void Var VarHolder VarIterator VarVisitor Format Pipe PipeImpl PipeStream SharedMemory \
|
||||
MemoryStream FileStream AtomicCounter DataURIStream DataURIStreamFactory
|
||||
|
||||
zlib_objects = adler32 compress crc32 deflate \
|
||||
|
99
Foundation/include/Poco/Dynamic/VarVisitor.h
Normal file
99
Foundation/include/Poco/Dynamic/VarVisitor.h
Normal file
@ -0,0 +1,99 @@
|
||||
#ifndef Foundation_VarVisitor_INCLUDED
|
||||
#define Foundation_VarVisitor_INCLUDED
|
||||
|
||||
//
|
||||
// VarVisitor.h
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Dynamic
|
||||
// Module: VarVisitor
|
||||
//
|
||||
// Definition of the VarVisitor class.
|
||||
//
|
||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Dynamic/Var.h"
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
namespace Poco {
|
||||
namespace Details {
|
||||
|
||||
struct TypeInfoHash
|
||||
{
|
||||
inline std::size_t operator()(std::type_info const& t) const { return t.hash_code(); }
|
||||
};
|
||||
|
||||
struct EqualRef
|
||||
{
|
||||
template <typename T>
|
||||
bool operator()(std::reference_wrapper<T> a, std::reference_wrapper<T> b) const
|
||||
{
|
||||
return a.get() == b.get();
|
||||
}
|
||||
};
|
||||
|
||||
using TypeInfoRef = std::reference_wrapper<std::type_info const>;
|
||||
|
||||
using HandlerCaller = std::function<void(const Poco::Dynamic::Var&)>;
|
||||
|
||||
template <typename T>
|
||||
using HandlerPointer = void (*)(const T &);
|
||||
|
||||
template <typename T>
|
||||
using Handler = std::function<void(const T&)>;
|
||||
|
||||
} // Details
|
||||
|
||||
namespace Dynamic {
|
||||
|
||||
class Foundation_API Visitor
|
||||
/// VarVisitor class.
|
||||
{
|
||||
std::unordered_map<Details::TypeInfoRef,
|
||||
Details::HandlerCaller,
|
||||
Details::TypeInfoHash,
|
||||
Details::EqualRef> _handlers;
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
bool addHandler(const Details::Handler<T> &f)
|
||||
/// Add handler for specific type T which holds in Var
|
||||
/// This method is more safe, because it saves copy of handler : lambda or std::function
|
||||
/// Returns true if handler was added
|
||||
{
|
||||
auto result = _handlers.emplace(std::ref(typeid(T)),
|
||||
Details::HandlerCaller([handler = f](const Poco::Dynamic::Var& x)
|
||||
{
|
||||
handler(x.extract<T>());
|
||||
}));
|
||||
return result.second;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool addHandler(Details::HandlerPointer<T> f)
|
||||
/// Add handler for specific type T which holds in Var
|
||||
/// This method is less safe, because it saves only copy of function pointer
|
||||
/// Returns true if handler was added
|
||||
{
|
||||
auto result = _handlers.emplace(std::ref(typeid(T)),
|
||||
Details::HandlerCaller([handlerPointer = f](const Poco::Dynamic::Var& x)
|
||||
{
|
||||
handlerPointer(x.extract<T>());
|
||||
}));
|
||||
return result.second;
|
||||
}
|
||||
|
||||
bool visit(const Poco::Dynamic::Var& x) const;
|
||||
/// Find handler for holded type and if it exists call handler
|
||||
/// Returns true if hanler was found othrewise returns false
|
||||
};
|
||||
|
||||
} } // namespace Poco::Dynamic
|
||||
|
||||
#endif // Foundation_VarVisitor_INCLUDED
|
32
Foundation/src/VarVisitor.cpp
Normal file
32
Foundation/src/VarVisitor.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// VarVisitor.cpp
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Dynamic
|
||||
// Module: VarVisitor
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
#include "Poco/Dynamic/VarVisitor.h"
|
||||
|
||||
namespace Poco {
|
||||
namespace Dynamic {
|
||||
|
||||
bool Visitor::visit(const Var &x) const
|
||||
{
|
||||
bool wasHandled = false;
|
||||
auto it = _handlers.find(x.type());
|
||||
if (it != _handlers.end())
|
||||
{
|
||||
it->second(x);
|
||||
wasHandled = true;
|
||||
}
|
||||
return wasHandled;
|
||||
}
|
||||
|
||||
} } // namespace Poco::Dynamic
|
@ -16,8 +16,10 @@
|
||||
#include "Poco/Bugcheck.h"
|
||||
#include "Poco/Dynamic/Struct.h"
|
||||
#include "Poco/Dynamic/Pair.h"
|
||||
#include "Poco/Dynamic/VarVisitor.h"
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1400
|
||||
@ -48,10 +50,15 @@ public:
|
||||
return _val;
|
||||
}
|
||||
|
||||
bool operator == (int i)
|
||||
bool operator == (int i) const
|
||||
{
|
||||
return i == _val;
|
||||
}
|
||||
|
||||
friend bool operator == (const Dummy &d1, const Dummy &d2)
|
||||
{
|
||||
return d1._val == d2._val;
|
||||
}
|
||||
|
||||
private:
|
||||
int _val;
|
||||
@ -3103,6 +3110,170 @@ void VarTest::testSharedPtr()
|
||||
assertTrue(p.referenceCount() == 1);
|
||||
}
|
||||
|
||||
struct ProcessDummy
|
||||
{
|
||||
Var &v;
|
||||
ProcessDummy(Var &var) : v(var) {}
|
||||
void operator()(const Dummy &d)
|
||||
{
|
||||
v = d;
|
||||
}
|
||||
};
|
||||
|
||||
#define ADD_HANDLER_FOR_TYPE_WITH_VALUE(Type, Handler, Value) \
|
||||
visitor.addHandler<Type>(Handler); \
|
||||
if (accepted) \
|
||||
{ \
|
||||
var.emplace_back(Type(Value));\
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
warn("handler already exists for " #Type "", __LINE__, __FILE__); \
|
||||
} void(0)
|
||||
|
||||
void VarTest::testVarVisitor()
|
||||
{
|
||||
Visitor visitor;
|
||||
Var processedVar;
|
||||
auto processInt8 = [&processedVar](const Poco::Int8 &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> Poco::Int8 ";
|
||||
};
|
||||
auto processInt16 = [&processedVar](const Poco::Int16 &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> Poco::Int16 ";
|
||||
};
|
||||
auto processInt32 = [&processedVar](const Poco::Int32 &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> Poco::Int32 ";
|
||||
};
|
||||
auto processInt64 = [&processedVar](const Poco::Int64 &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> Poco::Int64 ";
|
||||
};
|
||||
auto processUInt8 = [&processedVar](const Poco::UInt8 &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> Poco::UInt8 ";
|
||||
};
|
||||
auto processUInt16 = [&processedVar](const Poco::UInt16 &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> Poco::UInt16 ";
|
||||
};
|
||||
auto processUInt32 = [&processedVar](const Poco::UInt32 &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> Poco::UInt32 ";
|
||||
};
|
||||
auto processUInt64 = [&processedVar](const Poco::UInt64 &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> Poco::UInt64 ";
|
||||
};
|
||||
auto processBool = [&processedVar](const bool &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> bool ";
|
||||
};
|
||||
auto processChar = [&processedVar](const char &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> char ";
|
||||
};
|
||||
auto processFloat = [&processedVar](const float &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> float ";
|
||||
};
|
||||
auto processDouble = [&processedVar](const double &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> double ";
|
||||
};
|
||||
auto processLong = [&processedVar](const long &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> long ";
|
||||
};
|
||||
auto processLongLong = [&processedVar](const long long &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> long long ";
|
||||
};
|
||||
auto processULong = [&processedVar](const unsigned long &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> unsigned long ";
|
||||
};
|
||||
auto processULongLong = [&processedVar](const unsigned long long &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> unsigned long long ";
|
||||
};
|
||||
auto processString = [&processedVar](const std::string &v) -> void
|
||||
{
|
||||
processedVar = v;
|
||||
std::cout << " -> string ";
|
||||
};
|
||||
|
||||
std::vector<Var> var;
|
||||
|
||||
using ulong = unsigned long;
|
||||
using longlong = long long;
|
||||
using ulonglong = unsigned long long;
|
||||
|
||||
ProcessDummy processDummy(processedVar);
|
||||
|
||||
bool accepted = false;
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(Poco::Int8, processInt8, -8);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(Poco::Int16, processInt16, -16);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(Poco::Int32, processInt32, -32);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(Poco::Int64, processInt64, -64);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(Poco::UInt8, processUInt8, 8);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(Poco::UInt16, processUInt16, 16);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(Poco::UInt32, processUInt32, 32);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(Poco::UInt64, processUInt64, 64);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(bool, processBool, true);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(char, processChar, 'f');
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(float, processFloat, 1.2f);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(double, processDouble, 2.4);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(long, processLong, 123L);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(ulong, processULong, 124UL);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(longlong, processLongLong, 123123LL);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(ulonglong, processULongLong, 124124ULL);
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(std::string, processString, "hello world");
|
||||
accepted = ADD_HANDLER_FOR_TYPE_WITH_VALUE(Dummy, processDummy, 42);
|
||||
|
||||
for (const auto &v : var)
|
||||
{
|
||||
std::cout << "handle type : " << v.type().name();
|
||||
if (visitor.visit(v))
|
||||
{
|
||||
if (v.type() != typeid(Dummy))
|
||||
{
|
||||
std::cout << " [" << v.toString() << "] ... ";
|
||||
assertTrue(v == processedVar);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " [" << v.extract<Dummy>() << "] ... ";
|
||||
assertTrue(v.extract<Dummy>() == processedVar.extract<Dummy>());
|
||||
}
|
||||
std::cout << " ok" << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " fail" << '\n';
|
||||
fail(Poco::format("failed type handle : %s", v.type().name()), __LINE__, __FILE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VarTest::setUp()
|
||||
{
|
||||
@ -3172,6 +3343,7 @@ CppUnit::Test* VarTest::suite()
|
||||
CppUnit_addTest(pSuite, VarTest, testUUID);
|
||||
CppUnit_addTest(pSuite, VarTest, testEmpty);
|
||||
CppUnit_addTest(pSuite, VarTest, testIterator);
|
||||
CppUnit_addTest(pSuite, VarTest, testVarVisitor);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ public:
|
||||
void testEmpty();
|
||||
void testIterator();
|
||||
void testSharedPtr();
|
||||
void testVarVisitor();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
Loading…
x
Reference in New Issue
Block a user