Permalink
Browse files

String: number parsing & formatting

- ozCore
  * Math
    + isFinite(), isInf() isNaN() fixed
    + toBits(), fromBits()
  * String
    + parseBool(), parseInt(), parseFloat() ...
    + String(bool), String(int), String(float) ...
- unittest
  * string number creating/parsing test
  • Loading branch information...
1 parent c0f2f87 commit e6153be805532176cf838f7c8fecf390a088d936 @ducakar committed Jan 1, 2013
View
@@ -9,6 +9,7 @@
+ new Set template class: Map with arbitrary elements instead of key-value pairs
+ HashIndex and HashString merged into new HashMap template class with an arbitrary key type
+ new HashSet template class: hashtable of key-only elements instead of key-value pairs
+ * String: constructing from numbers, number parsing functions
* new Mat33 class
* SIMD support for linear algebra classes
* new SpinLock class
@@ -5,7 +5,7 @@
"crouchDimZ": 0.79,
"life": 100,
- "resistance": INF,
+ "resistance": inf,
"mass": 100,
"lift": 1.3,
@@ -27,7 +27,7 @@
"regeneration": 0,
"reachDist": 2,
- "grabWeight": INF,
+ "grabWeight": inf,
"throwMomentum": 10,
"nameList": "bogovi",
@@ -9,7 +9,7 @@
"dim": [ 2.99, 2.99, 2.99 ],
"life": 1,
- "resistance": INF,
+ "resistance": inf,
"onUpdate": "bigExplosion_onUpdate",
@@ -9,7 +9,7 @@
"dim": [ 0.15, 0.15, 0.15 ],
"life": 1,
- "resistance": INF,
+ "resistance": inf,
"imagoType": "SMM",
"imagoModel": "datacube"
@@ -9,7 +9,7 @@
"dim": [ 1.6, 1.6, 1.6 ],
"life": 1,
- "resistance": INF,
+ "resistance": inf,
"onUpdate": "smallExplosion_onUpdate",
View
@@ -79,7 +79,7 @@ void BSP::load()
mins = Point( -Math::INF, -Math::INF, -Math::INF );
maxs = Point( +Math::INF, +Math::INF, +Math::INF );
- if( Math::isnan( scale ) ) {
+ if( Math::isNaN( scale ) ) {
OZ_ERROR( "Invalid BSP config" );
}
@@ -964,7 +964,7 @@ void BSP::check() const
}
for( int i = 0; i < planes.length(); ++i ) {
- if( !Math::isfinite( planes[i].d ) ) {
+ if( !Math::isFinite( planes[i].d ) ) {
OZ_ERROR( "BSP has invalid plane %d", i );
}
}
View
@@ -52,7 +52,7 @@ void Caelum::build( const char* name )
p = 10.0f * Vec3( Math::centralRand(), Math::centralRand(), Math::centralRand() );
norm = p.sqN();
}
- while( Math::isnan( norm ) || norm < 25.0f || norm > 100.0f );
+ while( Math::isNaN( norm ) || norm < 25.0f || norm > 100.0f );
Vec3 z = ~p;
Vec3 x = ~Vec3( z.z, 0.0f, -z.x );
View
@@ -107,7 +107,7 @@ void Class::fillObject( const char* className )
if( life <= 0.0f || !Math::isnormal( life ) ) {
OZ_ERROR( "%s: Invalid life value. Should be > 0 and finite. If you want infinite life rather"
- " set resistance to infinity (\"inf\" or \"INF\").", className );
+ " set resistance to infinity (\"inf\").", className );
}
if( resistance < 0.0f ) {
OZ_ERROR( "%s: Invalid resistance. Should be >= 0.", className );
@@ -171,7 +171,7 @@ void NaClUpdater::downloadUpdates()
float progress = downloader.progress() * 100.0f;
- if( Math::isnan( progress ) ) {
+ if( Math::isNaN( progress ) ) {
NaClPlatform::post( String::str( "upd1:%d/%d", packageNum, nRemotePackages ) );
}
else {
View
@@ -27,13 +27,13 @@
#include "JSON.hh"
#include "List.hh"
+#include "SList.hh"
#include "Map.hh"
#include "HashMap.hh"
#include "System.hh"
#include "Log.hh"
#include <cstring>
-#include <sstream>
#define OZ_PARSE_ERROR( charBias, message ) \
OZ_ERROR( "JSON: " message " at %s:%d:%d", pos.path, pos.line, pos.column + ( charBias ) );
@@ -113,9 +113,11 @@ struct JSON::Parser
const char* path;
int line;
int column;
+ int oldLine;
+ int oldColumn;
char readChar();
- void back();
+ void backChar();
};
Position pos;
@@ -142,6 +144,9 @@ char JSON::Parser::Position::readChar()
OZ_PARSE_ERROR( 0, "Unexpected end of file" );
}
+ oldLine = line;
+ oldColumn = column;
+
char ch = istream->readChar();
if( ch == '\n' ) {
@@ -155,11 +160,12 @@ char JSON::Parser::Position::readChar()
}
OZ_HIDDEN
-void JSON::Parser::Position::back()
+void JSON::Parser::Position::backChar()
{
- hard_assert( istream->length() > 0 );
-
istream->setPos( istream->pos() - 1 );
+
+ line = oldLine;
+ column = oldColumn;
}
OZ_HIDDEN
@@ -203,7 +209,7 @@ JSON JSON::Parser::parse( InputStream* istream, const char* path )
OZ_HIDDEN
JSON::Parser::Parser( InputStream* istream, const char* path ) :
- pos( { istream, path, 1, 0 } )
+ pos( { istream, path, 1, 0, 1, 0 } )
{}
OZ_HIDDEN
@@ -309,47 +315,29 @@ JSON JSON::Parser::parseValue()
return JSON( new BooleanData( true ), BOOLEAN );
}
- default: { // number
- std::stringstream ss;
- ss.put( ch );
+ default: { // Number.
+ SList<char, 32> chars;
+ chars.add( ch );
while( pos.istream->isAvailable() ) {
ch = pos.readChar();
if( String::isBlank( ch ) || ch == ',' || ch == '}' || ch == ']' ) {
- pos.back();
+ pos.backChar();
break;
}
- ss.put( ch );
+ if( chars.length() == 32 ) {
+ OZ_PARSE_ERROR( -chars.length(), "Too long " );
+ }
+ chars.add( ch );
}
+ chars.add( '\0' );
- int nChars = int( ss.tellp() );
-
- float number;
- ss >> number;
-
- if( ss.fail() ) {
- std::string str = ss.str();
- const char* s = str.c_str();
- float sign = 1.0f;
-
- if( s[0] == '-' ) {
- sign = -1.0f;
- ++s;
- }
- else if( s[0] == '+' ) {
- ++s;
- }
+ const char* end;
+ float number = String::parseFloat( chars.begin(), &end );
- if( strcmp( s, "INF" ) == 0 ) {
- number = sign * Math::INF;
- }
- else if( strcmp( s, "NaN" ) == 0 ) {
- number = sign * Math::NaN;
- }
- else {
- OZ_PARSE_ERROR( -nChars, "Unknown value type" );
- }
+ if( end == chars.begin() ) {
+ OZ_PARSE_ERROR( -chars.length(), "Unknown value type" );
}
return JSON( new NumberData( number ), NUMBER );
@@ -374,7 +362,7 @@ JSON JSON::Parser::parseArray()
char ch = skipBlanks();
if( ch != ']' ) {
- pos.back();
+ pos.backChar();
}
while( ch != ']' ) {
@@ -399,7 +387,7 @@ JSON JSON::Parser::parseObject()
char ch = skipBlanks();
if( ch != '}' ) {
- pos.back();
+ pos.backChar();
}
while( ch != '}' ) {
@@ -447,7 +435,8 @@ void JSON::Parser::finish()
struct JSON::Formatter
{
- static const int ALIGNMENT_COLUMN = 32;
+ static const int ALIGNMENT_COLUMN = 32;
+ static const int SIGNIFICANT_DIGITS = 6;
BufferStream* ostream;
const char* lineEnd;
@@ -540,11 +529,8 @@ void JSON::Formatter::writeValue( const JSON& value )
case NUMBER: {
const NumberData* numberData = static_cast<const NumberData*>( value.data );
- std::stringstream ss;
- ss << numberData->value;
-
- int nChars = int( ss.tellp() );
- ss.read( ostream->forward( nChars ), nChars );
+ String s = String( numberData->value, SIGNIFICANT_DIGITS );
+ ostream->writeChars( s, s.length() );
break;
}
case STRING: {
@@ -2428,22 +2414,19 @@ String JSON::toString() const
return "null";
}
case BOOLEAN: {
- return static_cast<const BooleanData*>( data )->value ? "true" : "false";
+ const BooleanData* booleanData = static_cast<const BooleanData*>( data );
+
+ return booleanData->value ? "true" : "false";
}
case NUMBER: {
- std::stringstream ss;
- ss << static_cast<const NumberData*>( data )->value;
+ const NumberData* numberData = static_cast<const NumberData*>( data );
- int nChars = int( ss.tellp() );
- char* buffer;
- String r = String::create( nChars, &buffer );
- ss.read( buffer, nChars );
- buffer[nChars] = '\0';
-
- return r;
+ return String( numberData->value, Formatter::SIGNIFICANT_DIGITS );
}
case STRING: {
- return "\"" + static_cast<const StringData*>( data )->value + "\"";
+ const StringData* stringData = static_cast<const StringData*>( data );
+
+ return "\"" + stringData->value + "\"";
}
case ARRAY: {
const List<JSON>& list = static_cast<const ArrayData*>( data )->list;
View
@@ -37,7 +37,9 @@ namespace oz
/**
* DOM class for reading JSON configuration files.
*
- * Beside standard JSON format, `INF` and `NaN` (case sensitive) are also valid numbers.
+ * This implementation strictly follows JSON standard with the following exceptions:
+ * @li `inf` and `-inf` (case-sensitive) represent positive and negative infinity respectively,
+ * @li `nan` and `-nan` (case-sensitive) represent not-a-number.
*/
class JSON
{
Oops, something went wrong.

0 comments on commit e6153be

Please sign in to comment.