-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
Is Json::Value meant to be copyable?
Am I permitted to store it in a std::vector and then retrieve it later and call its methods?
I am developing and testing my own "path" method in a class built on top of JsonCpp. When using the path build into the JsonCpp library, it would crash with any path more than 1 level deep. So, I figured I'd roll my own. It also crashes on any level more than 1 deep when calling a method on a Json::Value that was stored in an std::vector.
It looks like it occurs on line 1003 of json_value.cpp is being triggered or an exception is thrown, but the type is an array value, so I don't understand what's going on. gtests is gobbling it up. I will try taking this code out of gtest in the meanwhile to see if it's an exception or the assert.
My method:
//--------------------------------------------------------------------------------------------------
// In development
std::vector<JsonLoader::JsonElement> JsonLoader::GetFromPath(const std::string & path)
{
std::vector<JsonElement> result;
JsonElement element;
element.m_key = "root";
element.m_value = m_root;
element.m_parent = Json::Value(NULL);
result.push_back(element);
// Tokenize the path
// Currently, the only path symbols we support are
// '/'
if (path.empty())
{
return result;
}
size_t currentPosition = 0;
char currentChar = path[currentPosition];
std::string currentToken;
std::deque<std::string> tokens;
if (currentChar != '$')
{
const std::string msg("Json path must begin with '$' for root.");
throw Shared::Exception(__FILE__, __LINE__, msg);
}
while(currentPosition < path.size() )
{
switch (currentChar)
{
case '$':
break;
case '.':
tokens.push_back(currentToken);
currentToken.clear();
break;
default:
currentToken.push_back(currentChar);
break;
}
++currentPosition;
currentChar = path[currentPosition];
}
if (!currentToken.empty() )
{
tokens.push_back(currentToken);
currentToken.clear();
}
std::vector<JsonElement> elementsLevelBeingSearched;
std::vector<JsonElement> elementsLevelToSearchNext;
elementsLevelToSearchNext.push_back(element);
for(size_t currentDepth = 0; currentDepth < tokens.size(); ++currentDepth)
{
elementsLevelBeingSearched = elementsLevelToSearchNext;
elementsLevelToSearchNext.clear();
for (std::vector<JsonElement>::iterator itElementsBeingSearched = elementsLevelBeingSearched.begin();
itElementsBeingSearched != elementsLevelBeingSearched.end(); ++itElementsBeingSearched)
{
JsonElement & elementBeingSearched = *itElementsBeingSearched;
// Crash occurs here on 2nd iteration of outter for loop
// with Path = "$people_with_jobs.jobs"
if ( elementBeingSearched.m_value.isMember(tokens[currentDepth]) )
{
element.m_key = tokens[currentDepth];
element.m_value = elementBeingSearched.m_value.get(tokens[currentDepth], Json::Value());
element.m_parent = elementBeingSearched.m_value;
elementsLevelToSearchNext.push_back(element);
}
}
}
return elementsLevelToSearchNext;
}class JsonLoader : public IJsonLoader
{
public:
// This struct is really just for easy debugging for now
struct JsonElement
{
std::string m_key;
Json::Value m_value;
Json::Value m_parent;
};
/// <summary>
/// Constructor
/// </summary>
JsonLoader(const std::string & json);
/// <summary>
/// Deconstructor
/// </summary>
virtual ~JsonLoader();
/// <summary>
/// Implements <c>IJsonLoader</c>
/// </summary>
virtual void Parse(const std::string & json,
const std::list<EntityDefinition::SharedPtr> & entityDefinitions);
protected:
Json::Value m_root;
/// <summary>
/// Based http://goessner.net/articles/JsonPath/
/// If the path references a non existant value Json::Value(NULL) is returned.
/// in development
/// </summary>
virtual std::vector<JsonElement> GetFromPath(const std::string & path);
};