110 lines
3.9 KiB
C++
110 lines
3.9 KiB
C++
// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey
|
|
// Please see LICENSE for license or visit https://github.com/taocpp/json/
|
|
|
|
#ifndef TAOCPP_JSON_INCLUDE_PATCH_HH
|
|
#define TAOCPP_JSON_INCLUDE_PATCH_HH
|
|
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
#include "value.hh"
|
|
#include "pointer.hh"
|
|
|
|
namespace tao
|
|
{
|
|
namespace json
|
|
{
|
|
template< template< typename ... > class Traits >
|
|
void patch_inplace( basic_value< Traits > & value, const basic_value< Traits > & patch )
|
|
{
|
|
for( const auto & entry : patch.get_array() ) {
|
|
const auto & op = entry.at( "op" ).get_string();
|
|
const auto & path = entry.at( "path" ).get_string();
|
|
const pointer path_pointer( path );
|
|
if ( op == "test" ) {
|
|
if ( value.at( path_pointer ) != entry.at( "value" ) ) {
|
|
throw std::runtime_error( "test failed for: " + path );
|
|
}
|
|
}
|
|
else if ( op == "remove" ) {
|
|
value.erase( path_pointer );
|
|
}
|
|
else if ( op == "add" ) {
|
|
value.insert( path_pointer, entry.at( "value" ) );
|
|
}
|
|
else if ( op == "replace" ) {
|
|
value.at( path_pointer ) = entry.at( "value" );
|
|
}
|
|
else if ( op == "move" ) {
|
|
const pointer from( entry.at( "from" ).get_string() );
|
|
auto v = std::move( value.at( from ) );
|
|
value.erase( from );
|
|
value.insert( path_pointer, std::move( v ) );
|
|
}
|
|
else if ( op == "copy" ) {
|
|
const pointer from( entry.at( "from" ).get_string() );
|
|
value.insert( path_pointer, value.at( from ) );
|
|
}
|
|
else {
|
|
throw std::runtime_error( "unknown patch operation: '" + op + '\'' );
|
|
}
|
|
}
|
|
}
|
|
|
|
template< template< typename ... > class Traits >
|
|
void patch_inplace( basic_value< Traits > & value, basic_value< Traits > && patch )
|
|
{
|
|
for( const auto & entry : patch.get_array() ) {
|
|
const auto & op = entry.at( "op" ).get_string();
|
|
const auto & path = entry.at( "path" ).get_string();
|
|
const pointer path_pointer( path );
|
|
if ( op == "test" ) {
|
|
if ( value.at( path_pointer ) != entry.at( "value" ) ) {
|
|
throw std::runtime_error( "test failed for: " + path );
|
|
}
|
|
}
|
|
else if ( op == "remove" ) {
|
|
value.erase( path_pointer );
|
|
}
|
|
else if ( op == "add" ) {
|
|
value.insert( path_pointer, std::move( entry.at( "value" ) ) );
|
|
}
|
|
else if ( op == "replace" ) {
|
|
value.at( path_pointer ) = std::move( entry.at( "value" ) );
|
|
}
|
|
else if ( op == "move" ) {
|
|
const pointer from( entry.at( "from" ).get_string() );
|
|
auto v = std::move( value.at( from ) );
|
|
value.erase( from );
|
|
value.insert( path_pointer, std::move( v ) );
|
|
}
|
|
else if ( op == "copy" ) {
|
|
const pointer from( entry.at( "from" ).get_string() );
|
|
value.insert( path_pointer, value.at( from ) );
|
|
}
|
|
else {
|
|
throw std::runtime_error( "unknown patch operation: '" + op + '\'' );
|
|
}
|
|
}
|
|
}
|
|
|
|
template< template< typename ... > class Traits >
|
|
basic_value< Traits > patch( basic_value< Traits > value, const basic_value< Traits > & patch )
|
|
{
|
|
patch_inplace( value, patch );
|
|
return std::move( value );
|
|
}
|
|
|
|
template< template< typename ... > class Traits >
|
|
basic_value< Traits > patch( basic_value< Traits > value, basic_value< Traits > && patch )
|
|
{
|
|
patch_inplace( value, std::move( patch ) );
|
|
return std::move( value );
|
|
}
|
|
|
|
} // json
|
|
|
|
} // tao
|
|
|
|
#endif
|