Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streaming JSON parser, helper for streaming arrays of small values #10

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -4
AlignAfterOpenBracket: true
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AlwaysBreakAfterDefinitionReturnType: false
AlwaysBreakAfterReturnType: All
AlwaysBreakTemplateDeclarations: true
AlwaysBreakBeforeMultilineStrings: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: false
BinPackArguments: false
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
IndentWrappedFunctionNames: false
IndentFunctionDeclarationAfterType: false
MaxEmptyLinesToKeep: 1
KeepEmptyLinesAtTheStartOfBlocks: true
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
SpacesBeforeTrailingComments: 2
Cpp11BracedListStyle: true
Standard: Auto
IndentWidth: 4
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Allman
SpacesInParentheses: true
SpacesInSquareBrackets: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpaceAfterCStyleCast: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
SpaceBeforeParens: ControlStatements
DisableFormat: false
...

257 changes: 257 additions & 0 deletions include/jsoncpp/json/forward_buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
#pragma once

#include <iostream>
#include <iterator>
#include <memory>
#include <sstream>
#include <vector>

namespace Json
{

/**
* Wraps a raw input stream into a buffered forward-iterator interface to
* allow parsing with backtracking.
*
* Iterators of this class mimic a raw character stream interface, with
* sensible implementations of pointer-arithmetic semantics. This allows
* it to slip underneath a string-based parsing implementation by acting
* like a contiguous character array of maximum size.
*
* A buffer may be initialized from a string or general input char stream.
*/
struct ForwardBuffer
{

/**
* Initialize a buffer from an input string.
*/
void
reset( const std::string &str_input )
{
this->owned_stream.reset( new std::istringstream( str_input ) );
reset( *( this->owned_stream ), str_input.size() );
}

/**
* Initialize a buffer from a character input stream.
*/
void
reset( std::istream &stream,
size_t input_size = std::numeric_limits<size_t>::max() )
{
reset( std::istreambuf_iterator<char>( stream ), input_size );
}

/**
* Initialize a buffer from a one-pass character stream iterator.
*/
void
reset( std::istreambuf_iterator<char> input,
size_t input_size = std::numeric_limits<size_t>::max() )
{
this->input = input;
this->input_size = input_size;
this->buffer.clear();
}

struct Iterator;

/**
* Re-initialize a buffer, discarding data before a particular buffer
* position.
*/
void
resetTo( Iterator it )
{
if ( it == end() )
{
this->buffer.clear();
this->input_size = 0;
return;
}

this->buffer.erase( buffer.begin(), it.raw() );
if ( this->input_size != std::numeric_limits<size_t>::max() )
this->input_size -= it.index;
}

/**
* Iterator mimics a character pointer array of configurable size - for
* unbounded streams it is an array of maximum size.
*/
struct Iterator
{

Iterator() : buffer( 0 ), index( 0 ) {}

Iterator( int ptr )
: buffer( reinterpret_cast<ForwardBuffer *>( ptr ) ), index( 0 )
{
}

Iterator( ForwardBuffer *buffer, size_t index )
: buffer( buffer ), index( index )
{
}

// ptr = 0
Iterator &
operator=( int ptr )
{
buffer = reinterpret_cast<ForwardBuffer *>( ptr );
return *this;
}

// if (ptr)
operator bool() const { return buffer != 0; }

// *ptr
const char &operator*() const { return buffer->buffer[index]; }

// ++ptr
Iterator operator++()
{
index = buffer->nextIndex( index );
return *this;
}

// ptr++
Iterator operator++( int )
{
Iterator result( *this );
++( *this );
return result;
}

// ptr_a == ptr_b
bool
operator==( const Iterator &other ) const
{
return index == other.index;
}

// ptr_a != ptr_b
bool
operator!=( const Iterator &other ) const
{
return !( *this == other );
}

// ptr_a < ptr_b
bool
operator<( const Iterator &other ) const
{
return index < other.index;
}

// ptr - 1
Iterator
operator-( int n ) const
{
return Iterator( buffer, index - n );
}

// ptr + 1
Iterator
operator+( int n ) const
{
return Iterator( buffer, index + n );
}

// ptr += 1
Iterator &
operator+=( int n )
{
for ( int i = 0; i < n; ++i ) index = buffer->nextIndex( index );
return *this;
}

// ptr_a - ptr_b
size_t
operator-( const Iterator &other ) const
{
return index - other.index;
}

// ptr[1]
const char &operator[]( size_t n ) const
{
return buffer->at( index + n );
}

/**
* Raw access to the buffer iterator, for std::string
*/
std::vector<char>::iterator
raw()
{
return buffer->buffer.begin() + index;
}

// We buffer sometimes in the background, but that shouldn't
// affect semantics
mutable ForwardBuffer *buffer;
size_t index;
};

Iterator
begin()
{
return Iterator( this, !bufferTo( 1 ) ? input_size : 0 );
}

Iterator
end()
{
return Iterator( this, input_size );
}

const char &
at( size_t index )
{
bufferTo( index + 1 );
return buffer[index];
}

bool
bufferTo( size_t size )
{
while ( buffer.size() < size )
{
if ( input == std::istreambuf_iterator<char>() ||
buffer.size() == input_size )
{
return false;
}
buffer.push_back( *input );
++input;
}

return true;
}

/**
* Increment index, where last index is at input_size and may be
* non-contiguous.
*/
size_t
nextIndex( size_t index )
{
if ( index == input_size ) return index;
return !bufferTo( ( index + 1 ) + 1 ) ? input_size : index + 1;
}

std::string
getBuffered()
{
return std::string( buffer.begin(), buffer.end() );
}

// Sometimes it's convenient to own the stream
std::unique_ptr<std::istream> owned_stream;
std::istreambuf_iterator<char> input;
size_t input_size;
std::vector<char> buffer;
};
}
Loading