Improved PropertyStream find and print routines

This commit is contained in:
NATTSiM
2014-01-08 11:03:15 -08:00
committed by Vinnie Falco
parent 1f9e2c920c
commit dda419ddd6
2 changed files with 321 additions and 55 deletions

View File

@@ -298,8 +298,24 @@ public:
will be nullptr and the second value will be undefined. will be nullptr and the second value will be undefined.
The second value is a boolean indicating whether or not the path string The second value is a boolean indicating whether or not the path string
specifies the wildcard character '*' as the last character. specifies the wildcard character '*' as the last character.
print statement examples
"parent.child" prints child and all of its children
"parent.child." start at the parent and print down to child
"parent.grandchild" prints nothing- grandchild not direct discendent
"parent.grandchild." starts at the parent and prints down to grandchild
"parent.grandchild.*" starts at parent, print through grandchild children
*/ */
std::pair <Source*, bool> find (std::string const& path); std::pair <Source*, bool> find (std::string path);
Source* find_one_deep (std::string const& name);
PropertyStream::Source* find_path(std::string path);
PropertyStream::Source* find_one(std::string const& name);
static bool peel_leading_slash (std::string* path);
static bool peel_trailing_slashstar (std::string* path);
static std::string peel_name(std::string* path);
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------

View File

@@ -20,6 +20,7 @@
#include "../PropertyStream.h" #include "../PropertyStream.h"
#include <limits> #include <limits>
#include <iostream>
namespace beast { namespace beast {
@@ -235,7 +236,7 @@ void PropertyStream::Source::write (
void PropertyStream::Source::write_one (PropertyStream& stream) void PropertyStream::Source::write_one (PropertyStream& stream)
{ {
Map map (m_name, stream); Map map (m_name, stream);
//onWrite (map); onWrite (map);
} }
void PropertyStream::Source::write (PropertyStream& stream) void PropertyStream::Source::write (PropertyStream& stream)
@@ -266,65 +267,111 @@ void PropertyStream::Source::write (PropertyStream& stream, std::string const& p
result.first->write_one (stream); result.first->write_one (stream);
} }
std::pair <PropertyStream::Source*, bool> PropertyStream::Source::find (std::string const& path) std::pair <PropertyStream::Source*, bool> PropertyStream::Source::find (std::string path)
{ {
struct Parser bool const deep (peel_trailing_slashstar (&path));
{ bool const rooted (peel_leading_slash (&path));
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 ())
return std::make_pair (this, false);
Parser p (path);
Source* source (this); Source* source (this);
if (p.next() != this->m_name) if (! path.empty())
return std::make_pair (nullptr, false);
for (;;)
{ {
std::string const s (p.next()); if (! rooted)
if (s.empty())
return std::make_pair (source, false);
if (s == "*")
return std::make_pair (source, true);
SharedState::Access state (source->m_state);
for (List <Item>::iterator iter (state->children.begin());;)
{ {
if (iter == state->children.end()) std::string const name (peel_name (&path));
return std::make_pair (nullptr, false); source = find_one_deep (name);
if (source == nullptr)
if (iter->source().m_name == s) return std::make_pair (nullptr, deep);
{
source = &iter->source();
break;
}
++iter;
} }
source = source->find_path (path);
} }
return std::make_pair (source, deep);
}
bool PropertyStream::Source::peel_leading_slash (std::string* path)
{
if (! path->empty() && path->front() == '/')
{
*path = std::string (path->begin() + 1, path->end());
return true;
}
return false;
}
bool PropertyStream::Source::peel_trailing_slashstar (std::string* path)
{
bool found(false);
if (path->empty())
return false;
if (path->back() == '*')
{
found = true;
path->pop_back();
}
if(! path->empty() && path->back() == '/')
path->pop_back();
return found;
}
std::string PropertyStream::Source::peel_name (std::string* path)
{
if (path->empty())
return "";
std::string::const_iterator first = (*path).begin();
std::string::const_iterator last = (*path).end();
std::string::const_iterator pos (std::find (first, last, '/'));
std::string s (first, pos);
if (pos != last)
*path = std::string (pos+1, last);
else
*path = std::string ();
return s;
}
// Recursive search through the whole tree until name is found
PropertyStream::Source* PropertyStream::Source::find_one_deep (std::string const& name)
{
Source* found = find_one (name);
if (found != nullptr)
return found;
SharedState::Access state (this->m_state);
for (auto iter : state->children)
{
found = iter.source().find_one_deep (name);
if (found != nullptr)
return found;
}
return nullptr;
}
PropertyStream::Source* PropertyStream::Source::find_path (std::string path)
{
if (path.empty())
return this;
Source* source (this);
do
{
std::string const name (peel_name (&path));
if(name.empty ())
break;
source = source->find_one(name);
}
while (source != nullptr);
return source;
}
// This function only looks at immediate children
// If no immediate children match, then return nullptr
PropertyStream::Source* PropertyStream::Source::find_one (std::string const& name)
{
SharedState::Access state (this->m_state);
for (auto iter : state->children)
{
if (iter.source().m_name == name)
return &iter.source();
}
return nullptr;
} }
void PropertyStream::Source::onWrite (Map&) void PropertyStream::Source::onWrite (Map&)
@@ -444,5 +491,208 @@ void PropertyStream::add (uint64 value)
} }
} }
//------------------------------------------------------------------------------
class PropertyStreamTests : public UnitTest
{
public:
typedef PropertyStream::Source Source;
void test_peel_name (std::string s, std::string const& expected,
std::string const& expected_remainder)
{
try
{
std::string const peeled_name = Source::peel_name (&s);
expect (peeled_name == expected);
expect (s == expected_remainder);
}
catch (...)
{
failException ();
}
}
void test_peel_leading_slash (std::string s, std::string const& expected,
bool should_be_found)
{
try
{
bool const found (Source::peel_leading_slash (&s));
expect (found == should_be_found);
expect (s == expected);
}
catch(...)
{
failException ();
}
}
void test_peel_trailing_slashstar (std::string s,
std::string const& expected_remainder, bool should_be_found)
{
try
{
bool const found (Source::peel_trailing_slashstar (&s));
expect (found == should_be_found);
expect (s == expected_remainder);
}
catch (...)
{
failException ();
}
}
void test_find_one (Source& root, Source* expected, std::string const& name)
{
try
{
Source* source (root.find_one (name));
expect (source == expected);
}
catch (...)
{
failException ();
}
}
void test_find_path (Source& root, std::string const& path,
Source* expected)
{
try
{
Source* source (root.find_path (path));
expect (source == expected);
}
catch (...)
{
failException ();
}
}
void test_find_one_deep (Source& root, std::string const& name,
Source* expected)
{
try
{
Source* source (root.find_one_deep (name));
expect (source == expected);
}
catch(...)
{
failException ();
}
}
void test_find (Source& root, std::string path, Source* expected,
bool expected_star)
{
try
{
auto const result (root.find (path));
expect (result.first == expected);
expect (result.second == expected_star);
}
catch (...)
{
failException ();
}
}
void runTest()
{
Source a ("a");
Source b ("b");
Source c ("c");
Source d ("d");
Source e ("e");
Source f ("f");
Source g ("g");
//
// a { b { d { f }, e }, c { g } }
//
a.add ( b );
a.add ( c );
c.add ( g );
b.add ( d );
b.add ( e );
d.add ( f );
beginTestCase ("peel_name");
test_peel_name ("a", "a", "");
test_peel_name ("foo/bar", "foo", "bar");
test_peel_name ("foo/goo/bar", "foo", "goo/bar");
test_peel_name ("", "", "");
beginTestCase ("peel_leading_slash");
test_peel_leading_slash ("foo/", "foo/", false);
test_peel_leading_slash ("foo", "foo", false);
test_peel_leading_slash ("/foo/", "foo/", true);
test_peel_leading_slash ("/foo", "foo", true);
beginTestCase ("peel_trailing_slashstar");
test_peel_trailing_slashstar ("/foo/goo/*", "/foo/goo", true);
test_peel_trailing_slashstar ("foo/goo/*", "foo/goo", true);
test_peel_trailing_slashstar ("/foo/goo/", "/foo/goo", false);
test_peel_trailing_slashstar ("foo/goo", "foo/goo", false);
test_peel_trailing_slashstar ("", "", false);
test_peel_trailing_slashstar ("/", "", false);
test_peel_trailing_slashstar ("/*", "", true);
test_peel_trailing_slashstar ("//", "/", false);
test_peel_trailing_slashstar ("**", "*", true);
test_peel_trailing_slashstar ("*/", "*", false);
beginTestCase ("find_one");
test_find_one (a, &b, "b");
test_find_one (a, nullptr, "d");
test_find_one (b, &e, "e");
test_find_one (d, &f, "f");
beginTestCase ("find_path");
test_find_path (a, "a", nullptr);
test_find_path (a, "e", nullptr);
test_find_path (a, "a/b", nullptr);
test_find_path (a, "a/b/e", nullptr);
test_find_path (a, "b/e/g", nullptr);
test_find_path (a, "b/e/f", nullptr);
test_find_path (a, "b", &b);
test_find_path (a, "b/e", &e);
test_find_path (a, "b/d/f", &f);
beginTestCase ("find_one_deep");
test_find_one_deep (a, "z", nullptr);
test_find_one_deep (a, "g", &g);
test_find_one_deep (a, "b", &b);
test_find_one_deep (a, "d", &d);
test_find_one_deep (a, "f", &f);
beginTestCase ("find");
test_find (a, "", &a, false);
test_find (a, "*", &a, true);
test_find (a, "/b", &b, false);
test_find (a, "b", &b, false);
test_find (a, "d", &d, false);
test_find (a, "/b*", &b, true);
test_find (a, "b*", &b, true);
test_find (a, "d*", &d, true);
test_find (a, "/b/*", &b, true);
test_find (a, "b/*", &b, true);
test_find (a, "d/*", &d, true);
test_find (a, "a", nullptr, false);
test_find (a, "/d", nullptr, false);
test_find (a, "/d*", nullptr, true);
test_find (a, "/d/*", nullptr, true);
}
PropertyStreamTests ()
: UnitTest ("PropertyStream", "beast")
{
}
};
static PropertyStreamTests propertyStreamTests;
} }