From 1b797548dff7e2475826ba29a71c3f496008988f Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sat, 14 Aug 2010 07:12:29 +0000 Subject: libgats gets it's own repo. The rest of the history is in my misc repo. --- default.bld | 62 ++++++++++++++++++++++ src/boolean.cpp | 42 +++++++++++++++ src/boolean.h | 27 ++++++++++ src/dictionary.cpp | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dictionary.h | 44 ++++++++++++++++ src/float.cpp | 0 src/float.h | 0 src/gatsstream.cpp | 29 +++++++++++ src/gatsstream.h | 24 +++++++++ src/integer.cpp | 27 ++++++++++ src/integer.h | 78 ++++++++++++++++++++++++++++ src/list.cpp | 33 ++++++++++++ src/list.h | 22 ++++++++ src/object.cpp | 55 ++++++++++++++++++++ src/object.h | 39 ++++++++++++++ src/packet.cpp | 10 ++++ src/packet.h | 29 +++++++++++ src/string.cpp | 38 ++++++++++++++ src/string.h | 26 ++++++++++ src/tests/int.cpp | 21 ++++++++ src/unit/basic.unit | 122 +++++++++++++++++++++++++++++++++++++++++++ 21 files changed, 873 insertions(+) create mode 100644 default.bld create mode 100644 src/boolean.cpp create mode 100644 src/boolean.h create mode 100644 src/dictionary.cpp create mode 100644 src/dictionary.h create mode 100644 src/float.cpp create mode 100644 src/float.h create mode 100644 src/gatsstream.cpp create mode 100644 src/gatsstream.h create mode 100644 src/integer.cpp create mode 100644 src/integer.h create mode 100644 src/list.cpp create mode 100644 src/list.h create mode 100644 src/object.cpp create mode 100644 src/object.h create mode 100644 src/packet.cpp create mode 100644 src/packet.h create mode 100644 src/string.cpp create mode 100644 src/string.h create mode 100644 src/tests/int.cpp create mode 100644 src/unit/basic.unit diff --git a/default.bld b/default.bld new file mode 100644 index 0000000..ae6c61b --- /dev/null +++ b/default.bld @@ -0,0 +1,62 @@ + +action "default" +{ + build: [targets("header-links"), "libgats.a"]; +} + +action "all" +{ + build: [targets("header-links"), "libgats.a", targets()]; +} + + +CXXFLAGS += "-ggdb -Wall"; + +target files("src/*.h").replace("src/", "gats/") +{ + tag "header-links"; + display "symlink"; + input OUTPUT.replace("gats/","src/"); + profile "build" + { + execute("ln -s ../${INPUT} ${OUTPUT}"); + } +} + +target "libgats.a" +{ + rule "lib"; + input files("src/*.cpp"); + CXXFLAGS += "-I. -Ilibbu++ -fPIC"; +} + +target files("src/tests/*.cpp").replace("src/","").replace(".cpp","") +{ + input "src/${OUTPUT}.cpp"; + rule "exe"; + tag ["tests", "general tests"]; + CXXFLAGS += "-I. -Ilibbu++"; + LDFLAGS += "-L. -lgats -Llibbu++ -lbu++"; +} + +target files("src/unit/*.unit").replace("src/","").replace(".unit","") +{ + input "src/${OUTPUT}.unit"; + rule "exe"; + requires "libbu++.a"; + tag ["tests", "unit tests"]; + CXXFLAGS += "-I."; + LDFLAGS += "-L. -lbu++ -lgats"; +} + +rule "unit" +{ + input "*.unit"; + output INPUT.replace(".unit", ".cpp"); + + profile "build" + { + execute("../libbu++/mkunit \"${INPUT}\" \"${OUTPUT}\""); + } +} + diff --git a/src/boolean.cpp b/src/boolean.cpp new file mode 100644 index 0000000..087845a --- /dev/null +++ b/src/boolean.cpp @@ -0,0 +1,42 @@ +#include "gats/boolean.h" + +#include + +Gats::Boolean::Boolean() : + bVal( false ) +{ +} + +Gats::Boolean::Boolean( bool bVal ) : + bVal( bVal ) +{ +} + +Gats::Boolean::~Boolean() +{ +} + +void Gats::Boolean::write( Bu::Stream &rOut ) const +{ + if( bVal ) + { + rOut.write("1", 1 ); + } + else + { + rOut.write("0", 1 ); + } +} + +void Gats::Boolean::read( Bu::Stream &rIn, char cType ) +{ + if( cType == '1' ) + { + bVal = true; + } + else + { + bVal = false; + } +} + diff --git a/src/boolean.h b/src/boolean.h new file mode 100644 index 0000000..3035b32 --- /dev/null +++ b/src/boolean.h @@ -0,0 +1,27 @@ +#ifndef GATS_BOOLEAN_H +#define GATS_BOOLEAN_H + +#include "gats/object.h" + +namespace Gats +{ + class Boolean : public Gats::Object + { + public: + Boolean(); + Boolean( bool bVal ); + virtual ~Boolean(); + + virtual Type getType() const { return typeBoolean; } + bool getValue() const { return bVal; } + void setValue( bool b ) { bVal = b; } + + virtual void write( Bu::Stream &rOut ) const; + virtual void read( Bu::Stream &rIn, char cType ); + + private: + bool bVal; + }; +}; + +#endif diff --git a/src/dictionary.cpp b/src/dictionary.cpp new file mode 100644 index 0000000..385960f --- /dev/null +++ b/src/dictionary.cpp @@ -0,0 +1,145 @@ +#include "gats/dictionary.h" + +#include "gats/boolean.h" +#include "gats/integer.h" +#include "gats/float.h" +#include "gats/string.h" +#include "gats/list.h" + +template<> +uint32_t Bu::__calcHashCode( const Gats::String &s ) +{ + return __calcHashCode( dynamic_cast(s) ); +} + +Gats::Dictionary::Dictionary() +{ +} + +Gats::Dictionary::~Dictionary() +{ + for( iterator i = begin(); i; i++ ) + { + delete *i; + } +} + +void Gats::Dictionary::write( Bu::Stream &rOut ) const +{ + rOut.write("d", 1 ); + for( const_iterator i= begin(); i; i++ ) + { + i.getKey().write( rOut ); + (*i)->write( rOut ); + } + rOut.write("e", 1 ); +} + +void Gats::Dictionary::read( Bu::Stream &rIn, char cType ) +{ + for(;;) + { + char cNext; + rIn.read( &cNext, 1 ); + if( cNext == 'e' ) + break; + if( cNext != 's' ) + throw Bu::ExceptionBase("You can only use strings as keys."); + Gats::String sKey; + sKey.read( rIn, cNext ); + + ((Bu::Hash *)this)->insert( + sKey, Gats::Object::read( rIn ) + ); + } +} + +void Gats::Dictionary::insert( const Bu::FString &sKey, int64_t i ) +{ + ((Bu::Hash *)this)->insert( + sKey, new Gats::Integer( i ) + ); +} + +void Gats::Dictionary::insert( const Bu::FString &sKey, bool b ) +{ + Bu::Hash::insert( + sKey, new Gats::Boolean( b ) + ); +} + +void Gats::Dictionary::insert( const Bu::FString &sKey, double d ) +{ +// Bu::Hash::insert( +// sKey, new Gats::Float( d ) +// ); +} + +void Gats::Dictionary::insert( const Bu::FString &sKey, const Bu::FString &s ) +{ + Bu::Hash::insert( + sKey, new Gats::String( s ) + ); +} + +bool Gats::Dictionary::getBool( const Bu::FString &sKey ) +{ + Gats::Boolean *pOb = dynamic_cast( get( sKey ) ); + if( pOb ) + throw Bu::ExceptionBase("Cannot cast item '%s' to bool.", + sKey.getStr() ); + + return pOb->getValue(); +} + +int64_t Gats::Dictionary::getInt( const Bu::FString &sKey ) +{ + Gats::Integer *pOb = dynamic_cast( get( sKey ) ); + if( pOb ) + throw Bu::ExceptionBase("Cannot cast item '%s' to int.", + sKey.getStr() ); + + return pOb->getValue(); +} + +double Gats::Dictionary::getFloat( const Bu::FString &sKey ) +{/* + Gats::Boolean *pOb = dynamic_cast( get( sKey ) ); + if( pOb ) + throw Bu::ExceptionBase("Cannot cast item '%s' to bool.", + sKey.getStr() ); + + return pOb->getValue();*/ + return 0.0; +} + +Bu::FString Gats::Dictionary::getStr( const Bu::FString &sKey ) +{ + Gats::String *pOb = dynamic_cast( get( sKey ) ); + if( pOb ) + throw Bu::ExceptionBase("Cannot cast item '%s' to string.", + sKey.getStr() ); + + return *pOb; +} + +Gats::List *Gats::Dictionary::getList( const Bu::FString &sKey ) +{ + Gats::List *pOb = dynamic_cast( get( sKey ) ); + if( pOb ) + throw Bu::ExceptionBase("Cannot cast item '%s' to list.", + sKey.getStr() ); + + return pOb; +} + +Gats::Dictionary *Gats::Dictionary::getDict( const Bu::FString &sKey ) +{ + Gats::Dictionary *pOb = dynamic_cast( get( sKey ) ); + if( pOb ) + throw Bu::ExceptionBase("Cannot cast item '%s' to dictionary.", + sKey.getStr() ); + + return pOb; +} + diff --git a/src/dictionary.h b/src/dictionary.h new file mode 100644 index 0000000..3bcaec6 --- /dev/null +++ b/src/dictionary.h @@ -0,0 +1,44 @@ +#ifndef GATS_DICTIONARY_H +#define GATS_DICTIONARY_H + +#include "gats/object.h" +#include "gats/string.h" +#include + +namespace Gats +{ + class List; + + class Dictionary : public Gats::Object, + public Bu::Hash + { + public: + Dictionary(); + virtual ~Dictionary(); + + virtual Type getType() const { return typeDictionary; } + virtual void write( Bu::Stream &rOut ) const; + virtual void read( Bu::Stream &rIn, char cType ); + + void insert( const Bu::FString &sKey, int64_t i ); + void insert( const Bu::FString &sKey, bool b ); + void insert( const Bu::FString &sKey, double d ); + void insert( const Bu::FString &sKey, const Bu::FString &s ); + using Bu::Hash::insert; + + bool getBool( const Bu::FString &sKey ); + int64_t getInt( const Bu::FString &sKey ); + double getFloat( const Bu::FString &sKey ); + Bu::FString getStr( const Bu::FString &sKey ); + Gats::List *getList( const Bu::FString &sKey ); + Gats::Dictionary *getDict( const Bu::FString &sKey ); + }; +}; + +namespace Bu +{ +template<> +uint32_t __calcHashCode( const Gats::String &s ); +}; + +#endif diff --git a/src/float.cpp b/src/float.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/float.h b/src/float.h new file mode 100644 index 0000000..e69de29 diff --git a/src/gatsstream.cpp b/src/gatsstream.cpp new file mode 100644 index 0000000..4b9cadf --- /dev/null +++ b/src/gatsstream.cpp @@ -0,0 +1,29 @@ +#include "gats/gatsstream.h" +#include "gats/object.h" + +#include +#include +using namespace Bu; + +Gats::GatsStream::GatsStream( Bu::Stream &rStream ) : + rStream( rStream ) +{ +} + +Gats::GatsStream::~GatsStream() +{ +} + +Gats::Object *Gats::GatsStream::readObject() +{ + +} + +void Gats::GatsStream::writeObject( Gats::Object *pObject ) +{ + Bu::NullStream ns; + pObject->write( ns ); + + sio << "Object consumed " << ns.tell() << "b." << sio.nl; +} + diff --git a/src/gatsstream.h b/src/gatsstream.h new file mode 100644 index 0000000..d668c28 --- /dev/null +++ b/src/gatsstream.h @@ -0,0 +1,24 @@ +#ifndef GATS_STREAM_H +#define GATS_STREAM_H + +#include + +namespace Gats +{ + class Object; + + class GatsStream + { + public: + GatsStream( Bu::Stream &rStream ); + virtual ~GatsStream(); + + Gats::Object *readObject(); + void writeObject( Gats::Object *pObject ); + + private: + Bu::Stream &rStream; + }; +}; + +#endif diff --git a/src/integer.cpp b/src/integer.cpp new file mode 100644 index 0000000..ad48eaf --- /dev/null +++ b/src/integer.cpp @@ -0,0 +1,27 @@ +#include "gats/integer.h" + +Gats::Integer::Integer() : + iVal( 0 ) +{ +} + +Gats::Integer::Integer( int64_t iVal ) : + iVal( iVal ) +{ +} + +Gats::Integer::~Integer() +{ +} + +void Gats::Integer::write( Bu::Stream &rOut ) const +{ + rOut.write("i", 1 ); + writePackedInt( rOut, iVal ); +} + +void Gats::Integer::read( Bu::Stream &rIn, char cType ) +{ + readPackedInt( rIn, iVal ); +} + diff --git a/src/integer.h b/src/integer.h new file mode 100644 index 0000000..6ed7c49 --- /dev/null +++ b/src/integer.h @@ -0,0 +1,78 @@ +#ifndef GATS_INTEGER_H +#define GATS_INTEGER_H + +#include "gats/object.h" + +#include + +#include + +namespace Gats +{ + class Integer : public Gats::Object + { + public: + Integer(); + Integer( int64_t iVal ); + virtual ~Integer(); + + virtual Type getType() const { return typeInteger; } + int64_t getValue() const { return iVal; } + + virtual void write( Bu::Stream &rOut ) const; + virtual void read( Bu::Stream &rIn, char cType ); + + template + static void readPackedInt( Bu::Stream &rStream, itype &rOut ) + { + int8_t b; + rOut = 0; + bool bNeg; + + rStream.read( &b, 1 ); + bNeg = ( b&0x40 ); + rOut |= (itype(b&0x3F)); + int c = 0; + while( (b&0x80) ) + { + rStream.read( &b, 1 ); + rOut |= (itype(b&0x7F)) << (6+7*(c++)); + } + if( bNeg ) rOut = -rOut; + } + + template + static void writePackedInt( Bu::Stream &rStream, itype iIn ) + { + uint8_t b; + + if( iIn < 0 ) + { + iIn = -iIn; + b = (iIn&0x3F) | 0x40; + } + else + { + b = (iIn&0x3F); + } + if( iIn > b ) + b |= 0x80; + rStream.write( &b, 1 ); + iIn = iIn >> 6; + + while( iIn ) + { + b = (iIn&0x7F); + if( iIn > b ) + b |= 0x80; + rStream.write( &b, 1 ); + iIn = iIn >> 7; + } + } + + private: + int64_t iVal; + }; +}; + +#endif diff --git a/src/list.cpp b/src/list.cpp new file mode 100644 index 0000000..995a764 --- /dev/null +++ b/src/list.cpp @@ -0,0 +1,33 @@ +#include "gats/list.h" + +#include + +Gats::List::List() +{ +} + +Gats::List::~List() +{ +} + +void Gats::List::write( Bu::Stream &rOut ) const +{ + rOut.write("l", 1 ); + for( const_iterator i = begin(); i; i++ ) + { + (*i)->write( rOut ); + } + rOut.write("e", 1 ); +} + +void Gats::List::read( Bu::Stream &rIn, char cType ) +{ + for(;;) + { + Gats::Object *pObj = Gats::Object::read( rIn ); + if( pObj == NULL ) + break; + append( pObj ); + } +} + diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..48faf23 --- /dev/null +++ b/src/list.h @@ -0,0 +1,22 @@ +#ifndef GATS_LIST_H +#define GATS_LIST_H + +#include "gats/object.h" +#include + +namespace Gats +{ + class List : public Gats::Object, public Bu::List + { + public: + List(); + virtual ~List(); + + virtual Type getType() const { return typeList; } + + virtual void write( Bu::Stream &rOut ) const; + virtual void read( Bu::Stream &rIn, char cType ); + }; +}; + +#endif diff --git a/src/object.cpp b/src/object.cpp new file mode 100644 index 0000000..3d7765e --- /dev/null +++ b/src/object.cpp @@ -0,0 +1,55 @@ +#include "gats/object.h" + +#include "gats/integer.h" +#include "gats/float.h" +#include "gats/boolean.h" +#include "gats/string.h" +#include "gats/list.h" +#include "gats/dictionary.h" + +#include + +Gats::Object::Object() +{ +} + +Gats::Object::~Object() +{ +} + +Gats::Object *Gats::Object::read( Bu::Stream &rIn ) +{ + char buf; + rIn.read( &buf, 1 ); + Object *pObj = NULL; + switch( buf ) + { + case 'i': + pObj = new Gats::Integer(); + break; + + case 's': + pObj = new Gats::String(); + break; + + case '0': + case '1': + pObj = new Gats::Boolean(); + break; + + case 'l': + pObj = new Gats::List(); + break; + + case 'e': + return NULL; + + default: + throw Bu::ExceptionBase("Invalid Gats type discovered: %c.", buf ); + } + + pObj->read( rIn, buf ); + + return pObj; +} + diff --git a/src/object.h b/src/object.h new file mode 100644 index 0000000..10bdc47 --- /dev/null +++ b/src/object.h @@ -0,0 +1,39 @@ +#ifndef GATS_OBJECT_H +#define GATS_OBJECT_H + +namespace Bu +{ + class Stream; +}; + +namespace Gats +{ + enum Type + { + typeDictionary, + typeList, + typeString, + typeInteger, + typeFloat, + typeBoolean + }; + + /** + * The baseclass for every type that can be stored in a packet. + */ + class Object + { + public: + Object(); + virtual ~Object(); + + virtual Type getType() const =0; + + virtual void write( Bu::Stream &rOut ) const=0; + virtual void read( Bu::Stream &rIn, char cType )=0; + + static Object *read( Bu::Stream &rIn ); + }; +}; + +#endif diff --git a/src/packet.cpp b/src/packet.cpp new file mode 100644 index 0000000..6283ce5 --- /dev/null +++ b/src/packet.cpp @@ -0,0 +1,10 @@ +#include "gats/packet.h" + +Gats::Packet::Packet() +{ +} + +Gats::Packet::~Packet() +{ +} + diff --git a/src/packet.h b/src/packet.h new file mode 100644 index 0000000..5ddc9ee --- /dev/null +++ b/src/packet.h @@ -0,0 +1,29 @@ +#ifndef GATS_PACKET_H +#define GATS_PACKET_H + +namespace Gats +{ + class Object; + + /** + * A D-encoded packet is a header and metadata related to encoding as well + * as a single object. The advantage of this method is that the packet + * contains all information related to encoding and is highly portable, it + * also lets the reader know how much data to expect, which makes this + * efficient for use in protocols and embedding in other data streams. + */ + class Packet + { + public: + Packet(); + Packet( Object *pObject ); + virtual ~Packet(); + + Object *getObject() { return pRoot; } + + private: + Object *pRoot; + }; +}; + +#endif diff --git a/src/string.cpp b/src/string.cpp new file mode 100644 index 0000000..416375d --- /dev/null +++ b/src/string.cpp @@ -0,0 +1,38 @@ +#include "gats/string.h" + +#include "gats/integer.h" + +Gats::String::String() +{ +} + +Gats::String::String( const String &s ) : + Bu::FString( s ) +{ +} + +Gats::String::String( const Bu::FString &s ) : + Bu::FString( s ) +{ +} + +Gats::String::~String() +{ +} + +void Gats::String::write( Bu::Stream &rOut ) const +{ + rOut.write("s", 1 ); + uint32_t iSize = getSize(); + Gats::Integer::writePackedInt( rOut, iSize ); + rOut.write( getStr(), iSize ); +} + +void Gats::String::read( Bu::Stream &rIn, char cType ) +{ + uint32_t iSize; + Gats::Integer::readPackedInt( rIn, iSize ); + setSize( iSize ); + rIn.read( getStr(), iSize ); +} + diff --git a/src/string.h b/src/string.h new file mode 100644 index 0000000..5343ba8 --- /dev/null +++ b/src/string.h @@ -0,0 +1,26 @@ +#ifndef GATS_STRING_H +#define GATS_STRING_H + +#include "gats/object.h" +#include + +namespace Gats +{ + class String : public Gats::Object, public Bu::FString + { + public: + String(); + String( const String &s ); + String( const Bu::FString &s ); + virtual ~String(); + + virtual Type getType() const { return typeString; } + + virtual void write( Bu::Stream &rOut ) const; + virtual void read( Bu::Stream &rIn, char cType ); + + private: + }; +}; + +#endif diff --git a/src/tests/int.cpp b/src/tests/int.cpp new file mode 100644 index 0000000..5d5b7d2 --- /dev/null +++ b/src/tests/int.cpp @@ -0,0 +1,21 @@ +#include "gats/integer.h" + +#include +#include + +using namespace Bu; + +int main() +{ + MemBuf mb; + int64_t i = -53954321995838ll; + + sio << "Before: " << i << sio.nl; + Gats::Integer::writePackedInt( mb, i ); + mb.setPos( 0 ); + Gats::Integer::readPackedInt( mb, i ); + sio << "After: " << i << sio.nl; + + return 0; +} + diff --git a/src/unit/basic.unit b/src/unit/basic.unit new file mode 100644 index 0000000..9389c70 --- /dev/null +++ b/src/unit/basic.unit @@ -0,0 +1,122 @@ +// vim: syntax=cpp +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "gats/dictionary.h" +#include "gats/integer.h" +#include "gats/float.h" +#include "gats/list.h" +#include "gats/boolean.h" +#include "gats/string.h" + +#include "bu/membuf.h" +#include "bu/list.h" +#include "bu/sio.h" + +#include + +using namespace Bu; + +suite Basic +{ + test integer + { + Bu::List lInts; + Bu::MemBuf mb; + + int64_t i = 1; + for( int x = 0; x < 256; x++ ) + { + lInts.append( i ); + Gats::Integer( i ).write( mb ); + i = -(i<<1)-i; + } + + mb.setPos( 0 ); + + for( Bu::List::iterator j = lInts.begin(); j; j++ ) + { + Gats::Object *pObj = Gats::Object::read( mb ); + if( pObj->getType() != Gats::typeInteger ) + unitFailed("Bad type read."); + + if( dynamic_cast(pObj)->getValue() != *j ) + unitFailed("Bad number."); + } + } + + test string + { + Bu::List lStrs; + Bu::MemBuf mb; + + lStrs.append( Bu::FString() ); + Gats::String("").write( mb ); + + { + int iMax = 0; + for( int j = 1; j <= (1<<16); j=j<<1 ) + iMax += j; + setStepCount( iMax ); + } + for( int j = 1; j <= (1<<16); j=j<<1 ) + { + Bu::FString s( j ); + for( int x = 0; x < j; x++ ) + { + s[x] = (unsigned char)(random()%256); + } + incProgress( j ); + Gats::String( s ).write( mb ); + lStrs.append( s ); + } + + mb.setPos( 0 ); + + for( Bu::List::iterator i = lStrs.begin(); i; i++ ) + { + Gats::Object *pObj = Gats::Object::read( mb ); + if( pObj->getType() != Gats::typeString ) + unitFailed("Bad type read."); + + if( *dynamic_cast(pObj) != *i ) + unitFailed("Bad string."); + } + } + + test boolean + { + Bu::List lBs; + Bu::MemBuf mb; + + for( int j = 0; j < 1024; j++ ) + { + if( random()%2 == 0 ) + { + lBs.append( true ); + Gats::Boolean( true ).write( mb ); + } + else + { + lBs.append( false ); + Gats::Boolean( false ).write( mb ); + } + } + + mb.setPos( 0 ); + + for( Bu::List::iterator i = lBs.begin(); i; i++ ) + { + Gats::Object *pObj = Gats::Object::read( mb ); + if( pObj->getType() != Gats::typeBoolean ) + unitFailed("Bad type read."); + + if( dynamic_cast(pObj)->getValue() != *i ) + unitFailed("Bad string."); + } + } +} -- cgit v1.2.3