Add PropertyStream for server state introspection

This commit is contained in:
Vinnie Falco
2013-10-07 13:26:56 -07:00
parent 24c2315476
commit 2c02580c37
2 changed files with 420 additions and 329 deletions

View File

@@ -26,182 +26,184 @@
#include "../threads/SharedData.h"
#include <string>
#include <utility>
namespace beast {
/** An output stream to procedurally generate an abstract property tree. */
//------------------------------------------------------------------------------
/** Abstract stream with RAII containers that produce a property tree. */
class PropertyStream
{
private:
class Proxy;
public:
class ScopedArray;
class ScopedObject;
class Map;
class Set;
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);
virtual ~PropertyStream ();
/** Object output.
*/
/** @{ */
void begin_object (std::string const& key) const;
void end_object () const;
protected:
virtual void map_begin () = 0;
virtual void map_begin (std::string const& key) = 0;
virtual void map_end () = 0;
virtual void add (std::string const& key, std::string const& value) = 0;
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
void lexical_add (std::string const &key, Value value)
{
std::stringstream ss;
ss << key;
write (ss.str(), value);
ss << value;
add (key, ss.str());
}
virtual void add (std::string const& key, int32 value);
virtual void add (std::string const& key, uint32 value);
virtual void add (std::string const& key, int64 value);
virtual void add (std::string const& key, uint64 value);
Proxy operator[] (std::string const& key) const;
virtual void array_begin () = 0;
virtual void array_begin (std::string const& key) = 0;
virtual void array_end () = 0;
template <typename Key>
Proxy operator[] (Key key) const;
/** @} */
/** Array output.
*/
/** @{ */
void begin_array (std::string const& key) const;
void end_array () const;
virtual void add (std::string const& value) = 0;
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; }
/** @} */
void lexical_add (Value value)
{
std::stringstream ss;
ss << value;
add (ss.str());
}
virtual void add ( int32 value);
virtual void add (uint32 value);
virtual void add ( int64 value);
virtual void add (uint64 value);
private:
static Sink& nullSink();
Sink* m_sink;
class Item;
class Proxy;
};
//------------------------------------------------------------------------------
//
// Item
//
class PropertyStream::Item : public List <Item>::Node
{
public:
explicit Item (Source* source);
Source& source() const;
Source* operator-> () const;
Source& operator* () const;
private:
Source* m_source;
};
//------------------------------------------------------------------------------
//
// Proxy
//
class PropertyStream::Proxy
{
private:
PropertyStream m_stream;
Map* m_map;
std::string m_key;
public:
Proxy (PropertyStream stream, std::string const& key);
Proxy (Map& map, std::string const& key);
template <typename Value>
Proxy& operator= (Value value)
{ m_stream.write (m_key, value); return *this; }
Proxy& operator= (Value value);
};
//------------------------------------------------------------------------------
//
// Map
//
template <typename Key>
PropertyStream::Proxy PropertyStream::operator[] (Key key) const
class PropertyStream::Map : public Uncopyable
{
std::stringstream ss;
ss << key;
return operator[] (ss.str());
private:
PropertyStream& m_stream;
public:
explicit Map (PropertyStream& stream);
explicit Map (Set& parent);
Map (std::string const& key, Map& parent);
Map (std::string const& key, PropertyStream& stream);
~Map ();
PropertyStream& stream();
PropertyStream const& stream() const;
template <typename Value>
void add (std::string const& key, Value value) const
{
m_stream.add (key, value);
}
template <typename Key, typename Value>
void add (Key key, Value value) const
{
std::stringstream ss;
ss << key;
add (ss.str(), value);
}
Proxy operator[] (std::string const& key);
Proxy operator[] (char const* key)
{ return Proxy (*this, key); }
template <typename Key>
Proxy operator[] (Key key) const
{
std::stringstream ss;
ss << key;
return Proxy (*this, ss.str());
}
};
//--------------------------------------------------------------------------
template <typename Value>
PropertyStream::Proxy& PropertyStream::Proxy::operator= (Value value)
{
m_map->add (m_key, value);
return *this;
}
//------------------------------------------------------------------------------
//--------------------------------------------------------------------------
//
// Set
//
class PropertyStream::ScopedObject
class PropertyStream::Set : public Uncopyable
{
private:
PropertyStream m_stream;
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 ();
explicit Set (Set& set);
Set (std::string const& key, Map& map);
Set (std::string const& key, PropertyStream& stream);
~Set ();
PropertyStream& stream();
PropertyStream const& stream() const;
template <typename Value>
void add (Value value) const
{ m_stream.add (value); }
};
//------------------------------------------------------------------------------
//
// Source
//
/** Subclasses can be called to write to a stream and have children. */
class PropertyStream::Source : public Uncopyable
@@ -213,6 +215,7 @@ private:
: item (source)
, parent (nullptr)
{ }
Item item;
Source* parent;
List <Item> children;
@@ -223,19 +226,27 @@ private:
std::string const m_name;
SharedState m_state;
void remove (SharedState::Access& state, SharedState::Access& childState);
//--------------------------------------------------------------------------
void remove (SharedState::Access& state,
SharedState::Access& childState);
void removeAll (SharedState::Access& state);
void write (SharedState::Access& state, PropertyStream& stream);
public:
explicit Source (std::string const& name);
~Source ();
/** Returns the name of this source. */
std::string const& name() const;
/** 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.
The source pointer is returned so it can be used in ctor-initializers.
*/
template <class Derived>
Derived* add (Derived* child)
@@ -244,20 +255,42 @@ public:
return child;
}
/** Remove a child source. */
/** Remove a child source from this Source. */
void remove (Source& child);
/** Remove all child sources. */
/** Remove all child sources of this Source. */
void removeAll ();
void write (PropertyStream stream, bool includeChildren);
void write (std::string const& path, PropertyStream stream);
/** Write only this Source to the stream. */
void write_one (PropertyStream& stream);
virtual void onWrite (PropertyStream) { }
/** write this source and all its children recursively to the stream. */
void write (PropertyStream& stream);
/** Parse the path and write the corresponding Source and optional children.
If the source is found, it is written. If the wildcard character '*'
exists as the last character in the path, then all the children are
written recursively.
*/
void write (PropertyStream& stream, std::string const& path);
/** Parse the dot-delimited Source path and return the result.
The first value will be a pointer to the Source object corresponding
to the given path. If no Source object exists, then the first value
will be nullptr and the second value will be undefined.
The second value is a boolean indicating whether or not the path string
specifies the wildcard character '*' as the last character.
*/
std::pair <Source*, bool> find (std::string const& path);
//--------------------------------------------------------------------------
/** Subclass override.
The default version does nothing.
*/
virtual void onWrite (Map&);
};
//------------------------------------------------------------------------------
}
#endif

View File

@@ -23,6 +23,12 @@
namespace beast {
//------------------------------------------------------------------------------
//
// Item
//
//------------------------------------------------------------------------------
PropertyStream::Item::Item (Source* source)
: m_source (source)
{
@@ -44,113 +50,110 @@ PropertyStream::Source& PropertyStream::Item::operator* () const
}
//------------------------------------------------------------------------------
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);
}
}
//
// Proxy
//
//------------------------------------------------------------------------------
PropertyStream::Proxy::Proxy (PropertyStream stream, std::string const& key)
: m_stream (stream)
PropertyStream::Proxy::Proxy (
Map& map, std::string const& key)
: m_map (&map)
, m_key (key)
{
}
//------------------------------------------------------------------------------
//
// Map
//
//------------------------------------------------------------------------------
PropertyStream::ScopedObject::ScopedObject (std::string const& key, PropertyStream stream)
PropertyStream::Map::Map (PropertyStream& stream)
: m_stream (stream)
{
m_stream.begin_object (key);
}
PropertyStream::ScopedObject::~ScopedObject ()
PropertyStream::Map::Map (Set& parent)
: m_stream (parent.stream())
{
m_stream.end_object ();
m_stream.map_begin ();
}
PropertyStream::Map::Map (std::string const& key, Map& map)
: m_stream (map.stream())
{
m_stream.map_begin (key);
}
PropertyStream::Map::Map (std::string const& key, PropertyStream& stream)
: m_stream (stream)
{
m_stream.map_begin (key);
}
PropertyStream::Map::~Map ()
{
m_stream.map_end ();
}
PropertyStream& PropertyStream::Map::stream()
{
return m_stream;
}
PropertyStream const& PropertyStream::Map::stream() const
{
return m_stream;
}
PropertyStream::Proxy PropertyStream::Map::operator[] (std::string const& key)
{
return Proxy (*this, key);
}
//------------------------------------------------------------------------------
//
// Set
//
//------------------------------------------------------------------------------
PropertyStream::ScopedArray::ScopedArray (std::string const& key, PropertyStream stream)
PropertyStream::Set::Set (Set& set)
: m_stream (set.m_stream)
{
m_stream.array_begin ();
}
PropertyStream::Set::Set (std::string const& key, Map& map)
: m_stream (map.stream())
{
m_stream.array_begin (key);
}
PropertyStream::Set::Set (std::string const& key, PropertyStream& stream)
: m_stream (stream)
{
m_stream.begin_array (key);
}
PropertyStream::ScopedArray::~ScopedArray ()
{
m_stream.end_array ();
m_stream.array_begin (key);
}
PropertyStream::Set::~Set ()
{
m_stream.array_end ();
}
PropertyStream& PropertyStream::Set::stream()
{
return m_stream;
}
PropertyStream const& PropertyStream::Set::stream() const
{
return m_stream;
}
//------------------------------------------------------------------------------
//
// Source
//
//------------------------------------------------------------------------------
PropertyStream::Source::Source (std::string const& name)
@@ -167,24 +170,9 @@ PropertyStream::Source::~Source ()
removeAll (state);
}
void PropertyStream::Source::remove (
SharedState::Access& state, SharedState::Access& childState)
std::string const& PropertyStream::Source::name () const
{
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);
}
return m_name;
}
void PropertyStream::Source::add (Source& source)
@@ -209,23 +197,57 @@ void PropertyStream::Source::removeAll ()
removeAll (state);
}
void PropertyStream::Source::write (PropertyStream stream, bool includeChildren)
{
ScopedObject child (m_name, stream);
onWrite (stream);
//------------------------------------------------------------------------------
if (includeChildren)
void PropertyStream::Source::write (
SharedState::Access& state, PropertyStream &stream)
{
for (List <Item>::iterator iter (state->children.begin());
iter != state->children.end(); ++iter)
{
SharedState::Access state (m_state);
for (List <Item>::iterator iter (state->children.begin());
iter != state->children.end(); ++iter)
{
(*iter)->write (stream, true);
}
Source& source (iter->source());
Map map (source.name(), stream);
source.write (stream);
}
}
void PropertyStream::Source::write (std::string const& path, PropertyStream stream)
//------------------------------------------------------------------------------
void PropertyStream::Source::write_one (PropertyStream& stream)
{
Map map (m_name, stream);
//onWrite (map);
}
void PropertyStream::Source::write (PropertyStream& stream)
{
Map map (m_name, stream);
onWrite (map);
SharedState::Access state (m_state);
for (List <Item>::iterator iter (state->children.begin());
iter != state->children.end(); ++iter)
{
Source& source (iter->source());
source.write (stream);
}
}
void PropertyStream::Source::write (PropertyStream& stream, std::string const& path)
{
std::pair <Source*, bool> result (find (path));
if (result.first == nullptr)
return;
if (result.second)
result.first->write (stream);
else
result.first->write_one (stream);
}
std::pair <PropertyStream::Source*, bool> PropertyStream::Source::find (std::string const& path)
{
struct Parser
{
@@ -251,114 +273,150 @@ void PropertyStream::Source::write (std::string const& path, PropertyStream stre
std::string::const_iterator m_last;
};
//-----------------------------------------
if (path.empty ())
{
write (stream, true);
return;
}
return std::make_pair (this, false);
Parser p (path);
Source* source (this);
if (p.next() != source->m_name)
return;
if (p.next() != this->m_name)
return std::make_pair (nullptr, false);
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;
}
return std::make_pair (source, false);
if (++iter == state->children.end())
return;
if (s == "*")
return std::make_pair (source, true);
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 std::make_pair (nullptr, false);
}
}
}
void PropertyStream::Source::onWrite (Map&)
{
}
//------------------------------------------------------------------------------
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);
}
}
//------------------------------------------------------------------------------
//
// PropertyStream
//
//------------------------------------------------------------------------------
PropertyStream::PropertyStream ()
: m_sink (&nullSink())
{
}
PropertyStream::PropertyStream (Sink& sink)
: m_sink (&sink)
PropertyStream::~PropertyStream ()
{
}
PropertyStream::PropertyStream (PropertyStream const& other)
: m_sink (other.m_sink)
void PropertyStream::add (std::string const& key, int32 value)
{
lexical_add (key, value);
}
PropertyStream& PropertyStream::operator= (PropertyStream const& other)
void PropertyStream::add (std::string const& key, uint32 value)
{
m_sink = other.m_sink;
return *this;
lexical_add (key, value);
}
PropertyStream::Proxy PropertyStream::operator[] (std::string const& key) const
void PropertyStream::add (std::string const& key, int64 value)
{
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 ();
}
void PropertyStream::begin_array (std::string const& key) const
{
m_sink->begin_array (key);
}
void PropertyStream::end_array () const
{
m_sink->end_array ();
}
PropertyStream::Sink& PropertyStream::nullSink()
{
struct NullSink : Sink
if (value <= std::numeric_limits <int32>::max() &&
value >= std::numeric_limits <int32>::min())
{
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;
add (key, int32(value));
}
else
{
lexical_add(key, value);
}
}
void PropertyStream::add (std::string const& key, uint64 value)
{
if (value <= std::numeric_limits <uint32>::max() &&
value >= std::numeric_limits <uint32>::min())
{
add (key, uint32(value));
}
else
{
lexical_add (key, value);
}
}
void PropertyStream::add (int32 value)
{
lexical_add (value);
}
void PropertyStream::add (uint32 value)
{
lexical_add (value);
}
void PropertyStream::add (int64 value)
{
if (value <= std::numeric_limits <int32>::max() &&
value >= std::numeric_limits <int32>::min())
{
add (int32(value));
}
else
{
lexical_add (value);
}
}
void PropertyStream::add (uint64 value)
{
if (value <= std::numeric_limits <uint32>::max() &&
value >= std::numeric_limits <uint32>::min())
{
add (uint32(value));
}
else
{
lexical_add (value);
}
}
}