Add PropertyStream

This commit is contained in:
Vinnie Falco
2013-10-06 11:07:25 -07:00
parent 3cf0729878
commit fcfa10d508
6 changed files with 619 additions and 0 deletions

View File

@@ -184,6 +184,7 @@
<ClInclude Include="..\..\beast\utility\Error.h" />
<ClInclude Include="..\..\beast\utility\Journal.h" />
<ClInclude Include="..\..\beast\utility\LeakChecked.h" />
<ClInclude Include="..\..\beast\utility\PropertyStream.h" />
<ClInclude Include="..\..\beast\utility\StaticObject.h" />
<ClInclude Include="..\..\beast\Version.h" />
<ClInclude Include="..\..\config\BeastConfig.h" />
@@ -569,6 +570,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\utility\impl\PropertyStream.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\utility\impl\StaticObject.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>

View File

@@ -1245,6 +1245,9 @@
<ClInclude Include="..\..\beast\Boost.h">
<Filter>beast</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\utility\PropertyStream.h">
<Filter>beast\utility</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\modules\beast_core\containers\AbstractFifo.cpp">
@@ -1793,6 +1796,9 @@
<ClCompile Include="..\..\beast\boost\Boost.cpp">
<Filter>beast\boost</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\utility\impl\PropertyStream.cpp">
<Filter>beast\utility\impl</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\TODO.txt">

View File

@@ -25,6 +25,7 @@
#include "utility/Error.h"
#include "utility/Journal.h"
#include "utility/LeakChecked.h"
#include "utility/PropertyStream.h"
#include "utility/StaticObject.h"
#endif

View File

@@ -0,0 +1,263 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED
#define BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED
#include "../CStdInt.h"
#include "../Uncopyable.h"
#include "../intrusive/List.h"
#include "../threads/SharedData.h"
#include <string>
namespace beast {
/** An output stream to procedurally generate an abstract property tree. */
class PropertyStream
{
private:
class Proxy;
public:
class ScopedArray;
class ScopedObject;
class Source;
private:
class Item : public List <Item>::Node
{
public:
explicit Item (Source* source);
Source& source() const;
Source* operator-> () const;
Source& operator* () const;
private:
Source* m_source;
};
public:
//--------------------------------------------------------------------------
class Sink : Uncopyable
{
public:
// Object output
//
// Default implementations convert to string
// Json doesn't support 64 bit so we convert these to string
// if they are outside the range of the corresponding 32 bit int
virtual void begin_object (std::string const& key) = 0;
virtual void end_object () = 0;
template <typename Value>
void lexical_write (std::string const &key, Value value)
{
std::stringstream ss;
ss << value;
write (key, ss.str());
}
virtual void write (std::string const& key, int32 value);
virtual void write (std::string const& key, uint32 value);
virtual void write (std::string const& key, int64 value);
virtual void write (std::string const& key, uint64 value);
virtual void write (std::string const& key, std::string const& value) = 0;
// Array output
//
virtual void begin_array (std::string const& key) = 0;
virtual void end_array () = 0;
template <typename Value>
void lexical_write (Value value)
{
std::stringstream ss;
ss << value;
write (ss.str());
}
virtual void write ( int32 value);
virtual void write (uint32 value);
virtual void write ( int64 value);
virtual void write (uint64 value);
virtual void write (std::string const& value) = 0;
};
//--------------------------------------------------------------------------
PropertyStream ();
PropertyStream (Sink& sink);
PropertyStream (PropertyStream const& other);
PropertyStream& operator= (PropertyStream const& other);
/** Object output.
*/
/** @{ */
void begin_object (std::string const& key) const;
void end_object () const;
template <typename Value>
void write (std::string const& key, Value value) const
{
m_sink->write (key, value);
}
template <typename Key, typename Value>
void write (Key key, Value value) const
{
std::stringstream ss;
ss << key;
write (ss.str(), value);
}
Proxy operator[] (std::string const& key) const;
template <typename Key>
Proxy operator[] (Key key) const;
/** @} */
/** Array output.
*/
/** @{ */
void begin_array (std::string const& key) const;
void end_array () const;
template <typename Value>
void append (Value value) const
{ m_sink->write (value); }
template <typename Value>
PropertyStream const& operator<< (Value value) const
{ append (value); return &this; }
/** @} */
private:
static Sink& nullSink();
Sink* m_sink;
};
//------------------------------------------------------------------------------
class PropertyStream::Proxy
{
private:
PropertyStream m_stream;
std::string m_key;
public:
Proxy (PropertyStream stream, std::string const& key);
template <typename Value>
Proxy& operator= (Value value)
{ m_stream.write (m_key, value); return *this; }
};
//------------------------------------------------------------------------------
template <typename Key>
PropertyStream::Proxy PropertyStream::operator[] (Key key) const
{
std::stringstream ss;
ss << key;
return operator[] (ss.str());
}
//------------------------------------------------------------------------------
class PropertyStream::ScopedObject
{
private:
PropertyStream m_stream;
public:
ScopedObject (std::string const& key, PropertyStream stream);
~ScopedObject ();
};
//------------------------------------------------------------------------------
class PropertyStream::ScopedArray
{
private:
PropertyStream m_stream;
public:
ScopedArray (std::string const& key, PropertyStream stream);
~ScopedArray ();
};
//------------------------------------------------------------------------------
/** Subclasses can be called to write to a stream and have children. */
class PropertyStream::Source : public Uncopyable
{
private:
struct State
{
explicit State (Source* source)
: item (source)
, parent (nullptr)
{ }
Item item;
Source* parent;
List <Item> children;
};
typedef SharedData <State> SharedState;
std::string const m_name;
SharedState m_state;
void remove (SharedState::Access& state, SharedState::Access& childState);
void removeAll (SharedState::Access& state);
public:
explicit Source (std::string const& name);
~Source ();
/** Add a child source. */
void add (Source& source);
/** Add a child source by pointer.
This returns the passed source so it can be conveniently chained
in ctor-initializer lists.
*/
template <class Derived>
Derived* add (Derived* child)
{
add (*static_cast <Source*>(child));
return child;
}
/** Remove a child source. */
void remove (Source& child);
/** Remove all child sources. */
void removeAll ();
void write (PropertyStream stream, bool includeChildren);
void write (std::string const& path, PropertyStream stream);
virtual void onWrite (PropertyStream) { }
};
//------------------------------------------------------------------------------
}
#endif

View File

@@ -28,3 +28,4 @@
#include "impl/Journal.cpp"
#include "impl/LeakChecked.cpp"
#include "impl/StaticObject.cpp"
#include "impl/PropertyStream.cpp"

View File

@@ -0,0 +1,341 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "../PropertyStream.h"
#include <limits>
namespace beast {
PropertyStream::Item::Item (Source* source)
: m_source (source)
{
}
PropertyStream::Source& PropertyStream::Item::source() const
{
return *m_source;
}
PropertyStream::Source* PropertyStream::Item::operator-> () const
{
return &source();
}
PropertyStream::Source& PropertyStream::Item::operator* () const
{
return source();
}
//------------------------------------------------------------------------------
void PropertyStream::Sink::write (std::string const& key, int32 value)
{
lexical_write (key, value);
}
void PropertyStream::Sink::write (std::string const& key, uint32 value)
{
lexical_write (key, value);
}
void PropertyStream::Sink::write (std::string const& key, int64 value)
{
if (value <= std::numeric_limits <int32>::max() &&
value >= std::numeric_limits <int32>::min())
{
write (key, int32(value));
}
else
{
lexical_write (key, value);
}
}
void PropertyStream::Sink::write (std::string const& key, uint64 value)
{
if (value <= std::numeric_limits <uint32>::max() &&
value >= std::numeric_limits <uint32>::min())
{
write (key, uint32(value));
}
else
{
lexical_write (key, value);
}
}
void PropertyStream::Sink::write (int32 value)
{
lexical_write (value);
}
void PropertyStream::Sink::write (uint32 value)
{
lexical_write (value);
}
void PropertyStream::Sink::write (int64 value)
{
if (value <= std::numeric_limits <int32>::max() &&
value >= std::numeric_limits <int32>::min())
{
write (int32(value));
}
else
{
lexical_write (value);
}
}
void PropertyStream::Sink::write (uint64 value)
{
if (value <= std::numeric_limits <uint32>::max() &&
value >= std::numeric_limits <uint32>::min())
{
write (uint32(value));
}
else
{
lexical_write (value);
}
}
//------------------------------------------------------------------------------
PropertyStream::Proxy::Proxy (PropertyStream stream, std::string const& key)
: m_stream (stream)
, m_key (key)
{
}
//------------------------------------------------------------------------------
PropertyStream::ScopedObject::ScopedObject (std::string const& key, PropertyStream stream)
: m_stream (stream)
{
m_stream.begin_object (key);
}
PropertyStream::ScopedObject::~ScopedObject ()
{
m_stream.end_object ();
}
//------------------------------------------------------------------------------
PropertyStream::Source::Source (std::string const& name)
: m_name (name)
, m_state (this)
{
}
PropertyStream::Source::~Source ()
{
SharedState::Access state (m_state);
if (state->parent != nullptr)
state->parent->remove (*this);
removeAll (state);
}
void PropertyStream::Source::remove (
SharedState::Access& state, SharedState::Access& childState)
{
bassert (childState->parent == this);
state->children.erase (
state->children.iterator_to (
childState->item));
childState->parent = nullptr;
}
void PropertyStream::Source::removeAll (SharedState::Access& state)
{
for (List <Item>::iterator iter (state->children.begin());
iter != state->children.end();)
{
SharedState::Access childState ((*iter)->m_state);
remove (state, childState);
}
}
void PropertyStream::Source::add (Source& source)
{
SharedState::Access state (m_state);
SharedState::Access childState (source.m_state);
bassert (childState->parent == nullptr);
state->children.push_back (childState->item);
childState->parent = this;
}
void PropertyStream::Source::remove (Source& child)
{
SharedState::Access state (m_state);
SharedState::Access childState (child.m_state);
remove (state, childState);
}
void PropertyStream::Source::removeAll ()
{
SharedState::Access state (m_state);
removeAll (state);
}
void PropertyStream::Source::write (PropertyStream stream, bool includeChildren)
{
ScopedObject child (m_name, stream);
onWrite (stream);
if (includeChildren)
{
SharedState::Access state (m_state);
for (List <Item>::iterator iter (state->children.begin());
iter != state->children.end(); ++iter)
{
(*iter)->write (stream, true);
}
}
}
void PropertyStream::Source::write (std::string const& path, PropertyStream stream)
{
struct Parser
{
Parser (std::string const& path)
: m_first (path.begin())
, m_last (path.end())
{
}
std::string next ()
{
std::string::const_iterator pos (
std::find (m_first, m_last, '.'));
std::string const s (m_first, pos);
if (pos != m_last)
m_first = pos + 1;
else
m_first = pos;
return s;
}
std::string::const_iterator m_first;
std::string::const_iterator m_last;
};
//-----------------------------------------
if (path.empty ())
{
write (stream, true);
return;
}
Parser p (path);
Source* source (this);
if (p.next() != source->m_name)
return;
for (;;)
{
std::string const s (p.next());
if (s.empty())
{
source->write (stream, false);
break;
}
else if (s == "*")
{
source->write (stream, true);
break;
}
else
{
SharedState::Access state (source->m_state);
for (List <Item>::iterator iter (state->children.begin());;)
{
if (iter->source().m_name == s)
{
source = &iter->source();
break;
}
if (++iter == state->children.end())
return;
}
}
}
}
//------------------------------------------------------------------------------
PropertyStream::PropertyStream ()
: m_sink (&nullSink())
{
}
PropertyStream::PropertyStream (Sink& sink)
: m_sink (&sink)
{
}
PropertyStream::PropertyStream (PropertyStream const& other)
: m_sink (other.m_sink)
{
}
PropertyStream& PropertyStream::operator= (PropertyStream const& other)
{
m_sink = other.m_sink;
return *this;
}
PropertyStream::Proxy PropertyStream::operator[] (std::string const& key) const
{
return Proxy (*this, key);
}
void PropertyStream::begin_object (std::string const& key) const
{
m_sink->begin_object (key);
}
void PropertyStream::end_object () const
{
m_sink->end_object ();
}
PropertyStream::Sink& PropertyStream::nullSink()
{
struct NullSink : Sink
{
void begin_object (std::string const&) { }
void end_object () { }
void write (std::string const&, std::string const&) { }
void begin_array (std::string const&) { }
void end_array () { }
void write (std::string const&) { }
};
static NullSink sink;
return sink;
}
}