From 6a7a44458431acee1fb2857c1130b47b4e704a28 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 23 Jul 2017 18:56:25 +0100 Subject: Adds the [input] streaming interfaces --- slicer/slicer/common.ice | 4 +++ slicer/slicer/modelPartsTypes.cpp | 12 +++++++++ slicer/slicer/modelPartsTypes.h | 50 ++++++++++++++++++++++++++++++++++++ slicer/slicer/modelPartsTypes.impl.h | 43 +++++++++++++++++++++++++++++++ slicer/slicer/slicer.cpp | 7 +++++ slicer/test/Jamfile.jam | 19 ++++++++++++++ slicer/test/expected/streamOut.json | 1 + slicer/test/expected/streamOut.xml | 13 ++++++++++ slicer/test/streams-mp.cpp | 5 ++++ slicer/test/streams.cpp | 46 +++++++++++++++++++++++++++++++++ slicer/test/streams.h | 12 +++++++++ 11 files changed, 212 insertions(+) create mode 100644 slicer/test/expected/streamOut.json create mode 100644 slicer/test/expected/streamOut.xml create mode 100644 slicer/test/streams-mp.cpp create mode 100644 slicer/test/streams.cpp create mode 100644 slicer/test/streams.h diff --git a/slicer/slicer/common.ice b/slicer/slicer/common.ice index 6960f42..9198aaa 100644 --- a/slicer/slicer/common.ice +++ b/slicer/slicer/common.ice @@ -38,6 +38,10 @@ module Slicer { string symbol; string type; }; + ["cpp:ice_print"] + exception InvalidStreamOperation extends SerializerError { + string method; + }; }; #endif diff --git a/slicer/slicer/modelPartsTypes.cpp b/slicer/slicer/modelPartsTypes.cpp index 801759d..c1661de 100644 --- a/slicer/slicer/modelPartsTypes.cpp +++ b/slicer/slicer/modelPartsTypes.cpp @@ -182,5 +182,17 @@ namespace Slicer { bool ModelPartForDictionaryBase::HasValue() const { return true; } ModelPartType ModelPartForDictionaryBase::GetType() const { return type; } const ModelPartType ModelPartForDictionaryBase::type = mpt_Dictionary; + + // Streams + ChildRefPtr ModelPartForStreamBase::GetAnonChildRef(const Slicer::HookFilter &) { throw InvalidStreamOperation(__FUNCTION__); } + ChildRefPtr ModelPartForStreamBase::GetChildRef(const std::string &, const Slicer::HookFilter &) { throw InvalidStreamOperation(__FUNCTION__); } + ModelPartType ModelPartForStreamBase::GetType() const { return mpt_Sequence; } + bool ModelPartForStreamBase::HasValue() const { return true; } + // Stream Roots + ModelPartForStreamRootBase::ModelPartForStreamRootBase(ModelPartPtr mp) : ModelPartForRootBase(mp) { } + void ModelPartForStreamRootBase::Write(Ice::OutputStreamPtr&) const { throw InvalidStreamOperation(__FUNCTION__); } + void ModelPartForStreamRootBase::Read(Ice::InputStreamPtr&) { throw InvalidStreamOperation(__FUNCTION__); } + bool ModelPartForStreamRootBase::HasValue() const { return mp->HasValue(); } + void ModelPartForStreamRootBase::OnEachChild(const ChildHandler & ch) { ch(GetRootName(), mp, NULL); } } diff --git a/slicer/slicer/modelPartsTypes.h b/slicer/slicer/modelPartsTypes.h index 2038350..69c29b3 100644 --- a/slicer/slicer/modelPartsTypes.h +++ b/slicer/slicer/modelPartsTypes.h @@ -310,6 +310,56 @@ namespace Slicer { static const std::string pairName; }; + template + class DLL_PUBLIC Stream { + public: + typedef boost::function Consumer; + typedef T element_type; + + virtual void Produce(const Consumer & c) = 0; + }; + + class DLL_PUBLIC ModelPartForStreamBase : public ModelPart { + public: + virtual ModelPartType GetType() const override; + virtual bool HasValue() const override; + virtual ChildRefPtr GetAnonChildRef(const HookFilter &) override; + virtual ChildRefPtr GetChildRef(const std::string &, const HookFilter &) override; + + virtual ModelPartPtr GetContainedModelPart() override = 0; + virtual void OnEachChild(const ChildHandler & ch) override = 0; + }; + + template + class DLL_PUBLIC ModelPartForStream : public ModelPartForStreamBase, ModelPartModel> { + public: + ModelPartForStream(Stream * s); + + virtual ModelPartPtr GetContainedModelPart() override; + virtual void OnEachChild(const ChildHandler & ch) override; + }; + + class DLL_PUBLIC ModelPartForStreamRootBase : public ModelPartForRootBase { + public: + ModelPartForStreamRootBase(ModelPartPtr mp); + + virtual void Write(Ice::OutputStreamPtr&) const override; + virtual void Read(Ice::InputStreamPtr&) override; + virtual bool HasValue() const override; + virtual void OnEachChild(const ChildHandler & ch) override; + virtual const std::string & GetRootName() const override = 0; + }; + + template + class DLL_PUBLIC ModelPartForStreamRoot : public ModelPartForStreamRootBase { + public: + ModelPartForStreamRoot(Stream * s); + + virtual const std::string & GetRootName() const override; + + private: + Stream * stream; + }; } #endif diff --git a/slicer/slicer/modelPartsTypes.impl.h b/slicer/slicer/modelPartsTypes.impl.h index 988d91e..3f701c2 100644 --- a/slicer/slicer/modelPartsTypes.impl.h +++ b/slicer/slicer/modelPartsTypes.impl.h @@ -24,6 +24,12 @@ #define MODELPARTFOR(Type, ModelPartType) \ CUSTOMMODELPARTFOR(Type, ModelPartType, ModelPartType) +#define MODELPARTFORSTREAM(StreamImpl) \ + namespace Slicer { \ + template<> ModelPartForRootPtr ModelPart::CreateRootFor(const StreamImpl & stream) { \ + return new ModelPartForStreamRoot(const_cast(&stream)); \ + } \ + } namespace Slicer { // ModelPartForRoot @@ -576,6 +582,43 @@ namespace Slicer { { return new ModelPartForStruct(nullptr); } + + // ModelPartForStream + template + ModelPartForStream::ModelPartForStream(Stream * s) : + ModelPartModel>(s) + { + } + + template + ModelPartPtr + ModelPartForStream::GetContainedModelPart() + { + return ModelPart::CreateFor(); + } + + template + void + ModelPartForStream::OnEachChild(const ChildHandler & ch) + { + BOOST_ASSERT(this->Model); + this->Model->Produce([&ch](const T & element) { + ch(ModelPartForSequence>::elementName, ModelPart::CreateFor(element), NULL); + }); + } + + template + ModelPartForStreamRoot::ModelPartForStreamRoot(Stream * s) : + ModelPartForStreamRootBase(new ModelPartForStream(s)) + { + } + + template + const std::string & + ModelPartForStreamRoot::GetRootName() const + { + return ModelPartForRoot>::rootName; + } } #endif diff --git a/slicer/slicer/slicer.cpp b/slicer/slicer/slicer.cpp index dbda326..ba4db3f 100644 --- a/slicer/slicer/slicer.cpp +++ b/slicer/slicer/slicer.cpp @@ -109,5 +109,12 @@ namespace Slicer { { CompilerErrorMsg::write(s, what); } + + AdHocFormatter(InvalidStreamOperationMsg, "%? is not valid on streams"); + void + InvalidStreamOperation::ice_print(std::ostream & s) const + { + InvalidStreamOperationMsg::write(s, method); + } } diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam index 53a9489..9a801c4 100644 --- a/slicer/test/Jamfile.jam +++ b/slicer/test/Jamfile.jam @@ -92,3 +92,22 @@ run serializers.cpp serializers ; +lib streams-mp : + streams-mp.cpp + : + common + types + ; + +run streams.cpp + helpers.cpp + : : : + streams-mp + types + common + ../slicer//slicer + ../slicer//slicer + ../xml//slicer-xml + ../json//slicer-json + ; + diff --git a/slicer/test/expected/streamOut.json b/slicer/test/expected/streamOut.json new file mode 100644 index 0000000..385fa12 --- /dev/null +++ b/slicer/test/expected/streamOut.json @@ -0,0 +1 @@ +["0","1","2","3","4","5","6","7","8","9"] diff --git a/slicer/test/expected/streamOut.xml b/slicer/test/expected/streamOut.xml new file mode 100644 index 0000000..a595ade --- /dev/null +++ b/slicer/test/expected/streamOut.xml @@ -0,0 +1,13 @@ + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + diff --git a/slicer/test/streams-mp.cpp b/slicer/test/streams-mp.cpp new file mode 100644 index 0000000..119ee1f --- /dev/null +++ b/slicer/test/streams-mp.cpp @@ -0,0 +1,5 @@ +#include +#include "streams.h" + +MODELPARTFORSTREAM(TestStream); + diff --git a/slicer/test/streams.cpp b/slicer/test/streams.cpp new file mode 100644 index 0000000..2f8a513 --- /dev/null +++ b/slicer/test/streams.cpp @@ -0,0 +1,46 @@ +#define BOOST_TEST_MODULE streams +#include + +#include +#include +#include +#include +#include +#include +#include "helpers.h" +#include "streams.h" + +void TestStream::Produce(const Consumer & c) +{ + for (int x = 0; x < 10; x += 1) { + auto str = boost::lexical_cast(x); + c(str); + } +} + +BOOST_FIXTURE_TEST_SUITE( stream, TestStream ); + +BOOST_AUTO_TEST_CASE( streamToXml ) +{ + const auto outputXml = binDir / "streamOut.xml"; + Slicer::SerializeAny(*this, outputXml); + diff(rootDir / "expected" / "streamOut.xml", outputXml); + auto seq = Slicer::DeserializeAny(outputXml); + BOOST_REQUIRE_EQUAL(10, seq.size()); + BOOST_REQUIRE_EQUAL("0", seq.front()); + BOOST_REQUIRE_EQUAL("9", seq.back()); +} + +BOOST_AUTO_TEST_CASE( streamToJson ) +{ + const auto outputJson = binDir / "streamOut.json"; + Slicer::SerializeAny(*this, outputJson); + diff(rootDir / "expected" / "streamOut.json", outputJson); + auto seq = Slicer::DeserializeAny(outputJson); + BOOST_REQUIRE_EQUAL(10, seq.size()); + BOOST_REQUIRE_EQUAL("0", seq.front()); + BOOST_REQUIRE_EQUAL("9", seq.back()); +} + +BOOST_AUTO_TEST_SUITE_END(); + diff --git a/slicer/test/streams.h b/slicer/test/streams.h new file mode 100644 index 0000000..28c0c9d --- /dev/null +++ b/slicer/test/streams.h @@ -0,0 +1,12 @@ +#ifndef SLICER_TEST_STREAMS_H +#define SLICER_TEST_STREAMS_H + +#include + +class TestStream : public Slicer::Stream { + public: + void Produce(const Consumer & c) override; +}; + +#endif + -- cgit v1.2.3