diff options
| author | Mike Buland <eichlan@xagasoft.com> | 2011-01-10 21:04:17 +0000 |
|---|---|---|
| committer | Mike Buland <eichlan@xagasoft.com> | 2011-01-10 21:04:17 +0000 |
| commit | 2ba3f84ab559da02a11aa000b3cecb3b3668af61 (patch) | |
| tree | 266f450b512f607ec54d54af4fa8c13fdbe7ef91 | |
| parent | ea18007633b31901f2ae275cc0576c3f7ce99fc9 (diff) | |
| parent | 3611f253f6fdfa4954d374ab85ddaa7f799c130c (diff) | |
| download | libbu++-2ba3f84ab559da02a11aa000b3cecb3b3668af61.tar.gz libbu++-2ba3f84ab559da02a11aa000b3cecb3b3668af61.tar.bz2 libbu++-2ba3f84ab559da02a11aa000b3cecb3b3668af61.tar.xz libbu++-2ba3f84ab559da02a11aa000b3cecb3b3668af61.zip | |
Merged in the core branch. This is a major update that fixes many things, and
changes many others, including source files that were deleted and renamed.
Before doing this update, I reccomend a full clean, or even a fresh checkout.
Things to note, most outstanding about this update:
- Bu::Socket was changed to Bu::TcpSocket and the default mode is blocking.
- All templatized container classes are SharedCore now, which is good, but
SharedCore is inherently non-reentrant safe. However, all SharedCore classes
have a "clone" function that return a non-shared copy of the object, safe for
passing into a reentrant safe function accessing shared memory.
Diffstat (limited to '')
| -rw-r--r-- | bnftest | 18 | ||||
| -rw-r--r-- | bnftest.2 | 24 | ||||
| -rw-r--r-- | default.bld | 16 | ||||
| -rw-r--r-- | src/archive.cpp | 9 | ||||
| -rw-r--r-- | src/archive.h | 4 | ||||
| -rw-r--r-- | src/archivebase.h | 5 | ||||
| -rw-r--r-- | src/array.h | 29 | ||||
| -rw-r--r-- | src/cachestorefiles.h | 2 | ||||
| -rw-r--r-- | src/cachestoremyriad.h | 2 | ||||
| -rw-r--r-- | src/client.cpp | 9 | ||||
| -rw-r--r-- | src/client.h | 8 | ||||
| -rw-r--r-- | src/fastcgi.cpp | 22 | ||||
| -rw-r--r-- | src/fastcgi.h | 18 | ||||
| -rw-r--r-- | src/fbasicstring.h | 241 | ||||
| -rw-r--r-- | src/file.cpp | 1 | ||||
| -rw-r--r-- | src/hash.h | 1057 | ||||
| -rw-r--r-- | src/heap.h | 300 | ||||
| -rw-r--r-- | src/httpget.h | 4 | ||||
| -rw-r--r-- | src/itoserver.cpp | 12 | ||||
| -rw-r--r-- | src/itoserver.h | 6 | ||||
| -rw-r--r-- | src/lexer.h | 4 | ||||
| -rw-r--r-- | src/list.h | 29 | ||||
| -rw-r--r-- | src/listhash.cpp | 8 | ||||
| -rw-r--r-- | src/listhash.h | 54 | ||||
| -rw-r--r-- | src/myriad.h | 2 | ||||
| -rw-r--r-- | src/myriadfs.cpp | 78 | ||||
| -rw-r--r-- | src/myriadfs.h | 54 | ||||
| -rw-r--r-- | src/newline.h | 2 | ||||
| -rw-r--r-- | src/paramproc.cpp | 523 | ||||
| -rw-r--r-- | src/paramproc.h | 163 | ||||
| -rw-r--r-- | src/parser.cpp | 34 | ||||
| -rw-r--r-- | src/parser.h | 5 | ||||
| -rw-r--r-- | src/ringbuffer.h | 209 | ||||
| -rw-r--r-- | src/server.cpp | 14 | ||||
| -rw-r--r-- | src/server.h | 6 | ||||
| -rw-r--r-- | src/set.h | 760 | ||||
| -rw-r--r-- | src/sharedcore.h | 77 | ||||
| -rw-r--r-- | src/tcpserversocket.cpp (renamed from src/serversocket.cpp) | 36 | ||||
| -rw-r--r-- | src/tcpserversocket.h (renamed from src/serversocket.h) | 18 | ||||
| -rw-r--r-- | src/tcpsocket.cpp (renamed from src/socket.cpp) | 148 | ||||
| -rw-r--r-- | src/tcpsocket.h (renamed from src/socket.h) | 31 | ||||
| -rw-r--r-- | src/tests/sharedcore.cpp | 2 | ||||
| -rw-r--r-- | src/tests/socketblock.cpp | 10 | ||||
| -rw-r--r-- | src/tests/socketbreak.cpp | 10 | ||||
| -rw-r--r-- | src/tests/tcpsocket.cpp (renamed from src/tests/socket.cpp) | 4 | ||||
| -rw-r--r-- | src/tools/bnfcompile.cpp | 410 | ||||
| -rw-r--r-- | src/tools/myriadfs.cpp | 38 | ||||
| -rw-r--r-- | src/tools/parser.cpp | 89 | ||||
| -rw-r--r-- | src/unit/fstring.unit | 9 | ||||
| -rw-r--r-- | src/unit/hash.unit | 13 | ||||
| -rw-r--r-- | src/utfstring.cpp | 29 | ||||
| -rw-r--r-- | src/utfstring.h | 24 | ||||
| -rw-r--r-- | src/variant.h | 18 |
53 files changed, 2221 insertions, 2477 deletions
| @@ -0,0 +1,18 @@ | |||
| 1 | tokens = tokPlus tokMinus tokMult tokDivide tokOpenParen tokCloseParen | ||
| 2 | tokEquals tokNumber; | ||
| 3 | |||
| 4 | input: input line | ||
| 5 | | | ||
| 6 | ; | ||
| 7 | |||
| 8 | line: expr tokEquals {print} | ||
| 9 | ; | ||
| 10 | |||
| 11 | expr: expr tokPlus expr {add} | ||
| 12 | | expr tokMinus expr {subtract} | ||
| 13 | | expr tokMult expr {multiply} | ||
| 14 | | expr tokDivide expr {divide} | ||
| 15 | | tokOpenParen expr tokCloseParen | ||
| 16 | | [tokNumber] | ||
| 17 | ; | ||
| 18 | |||
diff --git a/bnftest.2 b/bnftest.2 new file mode 100644 index 0000000..229943b --- /dev/null +++ b/bnftest.2 | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | tokens = tokPlus tokMinus tokMult tokDivide tokOpenParen tokCloseParen | ||
| 2 | tokEquals tokNumber; | ||
| 3 | |||
| 4 | input: line input# | ||
| 5 | | | ||
| 6 | ; | ||
| 7 | |||
| 8 | input#: line input# | ||
| 9 | | | ||
| 10 | ; | ||
| 11 | |||
| 12 | line: expr tokEquals {print} | ||
| 13 | ; | ||
| 14 | |||
| 15 | expr: tokOpenParen expr tokCloseParen expr# | ||
| 16 | | [tokNumber] expr# | ||
| 17 | ; | ||
| 18 | |||
| 19 | expr#: tokPlus expr {add} expr# | ||
| 20 | | tokMinus expr {subtract} expr# | ||
| 21 | | tokMult expr {multiply} expr# | ||
| 22 | | tokDivide expr {divide} expr# | ||
| 23 | | | ||
| 24 | ; | ||
diff --git a/default.bld b/default.bld index 857e988..50baefb 100644 --- a/default.bld +++ b/default.bld | |||
| @@ -82,6 +82,22 @@ target "viewcsv" | |||
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | // | 84 | // |
| 85 | // This shouldn't be. Basically, if you set a property on a top level target | ||
| 86 | // that has children it seems like the items should apply to the children. | ||
| 87 | // I'm honestly not 100% sure what the policy should be yet, but this seems like | ||
| 88 | // I shouldn't have to do it this way. | ||
| 89 | // | ||
| 90 | target "src/tools/myriadfs.o" | ||
| 91 | { | ||
| 92 | CXXFLAGS += "-D_FILE_OFFSET_BITS=64"; | ||
| 93 | } | ||
| 94 | |||
| 95 | target "myriadfs" | ||
| 96 | { | ||
| 97 | LDFLAGS += "-lfuse"; | ||
| 98 | } | ||
| 99 | |||
| 100 | // | ||
| 85 | // General Tests | 101 | // General Tests |
| 86 | // | 102 | // |
| 87 | 103 | ||
diff --git a/src/archive.cpp b/src/archive.cpp index 69d4a0c..7a10921 100644 --- a/src/archive.cpp +++ b/src/archive.cpp | |||
| @@ -22,20 +22,15 @@ Bu::Archive::~Archive() | |||
| 22 | { | 22 | { |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | void Bu::Archive::write( const void *pData, int32_t nSize ) | 25 | void Bu::Archive::write( const void *pData, size_t nSize ) |
| 26 | { | 26 | { |
| 27 | if( nSize == 0 || pData == NULL ) | 27 | if( nSize == 0 || pData == NULL ) |
| 28 | return; | 28 | return; |
| 29 | 29 | ||
| 30 | // Bu::sio << "Writing starting at pos: " << rStream.tell() << " - " | ||
| 31 | // << Bu::sio.flush; | ||
| 32 | |||
| 33 | rStream.write( (const char *)pData, nSize ); | 30 | rStream.write( (const char *)pData, nSize ); |
| 34 | // | ||
| 35 | // Bu::sio << rStream.tell() << " (" << nSize << "b)" << Bu::sio.nl; | ||
| 36 | } | 31 | } |
| 37 | 32 | ||
| 38 | void Bu::Archive::read( void *pData, int32_t nSize ) | 33 | void Bu::Archive::read( void *pData, size_t nSize ) |
| 39 | { | 34 | { |
| 40 | if( nSize == 0 || pData == NULL ) | 35 | if( nSize == 0 || pData == NULL ) |
| 41 | return; | 36 | return; |
diff --git a/src/archive.h b/src/archive.h index bd85113..9d2aee2 100644 --- a/src/archive.h +++ b/src/archive.h | |||
| @@ -83,8 +83,8 @@ namespace Bu | |||
| 83 | virtual ~Archive(); | 83 | virtual ~Archive(); |
| 84 | virtual void close(); | 84 | virtual void close(); |
| 85 | 85 | ||
| 86 | virtual void write(const void *, int32_t); | 86 | virtual void write( const void *pData, size_t iSize ); |
| 87 | virtual void read(void *, int32_t); | 87 | virtual void read( void *pData, size_t iSize ); |
| 88 | 88 | ||
| 89 | /** | 89 | /** |
| 90 | * For storage, get an ID for the pointer to the object you're going to | 90 | * For storage, get an ID for the pointer to the object you're going to |
diff --git a/src/archivebase.h b/src/archivebase.h index c871bb5..18591f0 100644 --- a/src/archivebase.h +++ b/src/archivebase.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #define BU_ARCHIVE_BASE_H | 9 | #define BU_ARCHIVE_BASE_H |
| 10 | 10 | ||
| 11 | #include <stdint.h> | 11 | #include <stdint.h> |
| 12 | #include <unistd.h> | ||
| 12 | 13 | ||
| 13 | namespace Bu | 14 | namespace Bu |
| 14 | { | 15 | { |
| @@ -19,8 +20,8 @@ namespace Bu | |||
| 19 | virtual ~ArchiveBase(); | 20 | virtual ~ArchiveBase(); |
| 20 | 21 | ||
| 21 | virtual void close()=0; | 22 | virtual void close()=0; |
| 22 | virtual void write( const void *pData, int32_t iLength )=0; | 23 | virtual void write( const void *pData, size_t iLength )=0; |
| 23 | virtual void read( void *pData, int32_t iLength )=0; | 24 | virtual void read( void *pData, size_t iLength )=0; |
| 24 | virtual bool isLoading()=0; | 25 | virtual bool isLoading()=0; |
| 25 | }; | 26 | }; |
| 26 | 27 | ||
diff --git a/src/array.h b/src/array.h index eeee677..f225c97 100644 --- a/src/array.h +++ b/src/array.h | |||
| @@ -18,9 +18,18 @@ namespace Bu | |||
| 18 | subExceptionDecl( ArrayException ) | 18 | subExceptionDecl( ArrayException ) |
| 19 | 19 | ||
| 20 | template<typename value, int inc, typename valuealloc> | 20 | template<typename value, int inc, typename valuealloc> |
| 21 | class Array; | ||
| 22 | |||
| 23 | /** @cond DEVEL */ | ||
| 24 | template<typename value, int inc, typename valuealloc> | ||
| 21 | class ArrayCore | 25 | class ArrayCore |
| 22 | { | 26 | { |
| 23 | public: | 27 | friend class Array<value, inc, valuealloc>; |
| 28 | friend class SharedCore< | ||
| 29 | Array<value, inc, valuealloc>, | ||
| 30 | ArrayCore<value, inc, valuealloc> | ||
| 31 | >; | ||
| 32 | private: | ||
| 24 | ArrayCore() : | 33 | ArrayCore() : |
| 25 | pData( NULL ), | 34 | pData( NULL ), |
| 26 | iSize( 0 ), | 35 | iSize( 0 ), |
| @@ -99,6 +108,7 @@ namespace Bu | |||
| 99 | long iSize; | 108 | long iSize; |
| 100 | long iCapacity; | 109 | long iCapacity; |
| 101 | }; | 110 | }; |
| 111 | /** @endcond */ | ||
| 102 | 112 | ||
| 103 | /** | 113 | /** |
| 104 | * Array type container, just like a normal array only flexible and keeps | 114 | * Array type container, just like a normal array only flexible and keeps |
| @@ -110,16 +120,20 @@ namespace Bu | |||
| 110 | *@ingroup Containers | 120 | *@ingroup Containers |
| 111 | */ | 121 | */ |
| 112 | template<typename value, int inc=10, typename valuealloc=std::allocator<value> > | 122 | template<typename value, int inc=10, typename valuealloc=std::allocator<value> > |
| 113 | class Array : public SharedCore<ArrayCore<value, inc, valuealloc> > | 123 | class Array : public SharedCore< |
| 124 | Array<value, inc, valuealloc>, | ||
| 125 | ArrayCore<value, inc, valuealloc> | ||
| 126 | > | ||
| 114 | { | 127 | { |
| 115 | private: | 128 | private: |
| 116 | typedef class Array<value, inc, valuealloc> MyType; | 129 | typedef class Array<value, inc, valuealloc> MyType; |
| 117 | typedef class ArrayCore<value, inc, valuealloc> Core; | 130 | typedef class ArrayCore<value, inc, valuealloc> Core; |
| 118 | 131 | ||
| 119 | protected: | 132 | protected: |
| 120 | using SharedCore< Core >::core; | 133 | using SharedCore<MyType, Core>::core; |
| 121 | using SharedCore< Core >::_hardCopy; | 134 | using SharedCore<MyType, Core>::_hardCopy; |
| 122 | using SharedCore< Core >::_allocateCore; | 135 | using SharedCore<MyType, Core>::_resetCore; |
| 136 | using SharedCore<MyType, Core>::_allocateCore; | ||
| 123 | 137 | ||
| 124 | public: | 138 | public: |
| 125 | struct const_iterator; | 139 | struct const_iterator; |
| @@ -130,7 +144,7 @@ namespace Bu | |||
| 130 | } | 144 | } |
| 131 | 145 | ||
| 132 | Array( const MyType &src ) : | 146 | Array( const MyType &src ) : |
| 133 | SharedCore< Core >( src ) | 147 | SharedCore<MyType, Core >( src ) |
| 134 | { | 148 | { |
| 135 | } | 149 | } |
| 136 | 150 | ||
| @@ -168,8 +182,7 @@ namespace Bu | |||
| 168 | */ | 182 | */ |
| 169 | void clear() | 183 | void clear() |
| 170 | { | 184 | { |
| 171 | _hardCopy(); | 185 | _resetCore(); |
| 172 | core->clear(); | ||
| 173 | } | 186 | } |
| 174 | 187 | ||
| 175 | MyType &append( const value &rVal ) | 188 | MyType &append( const value &rVal ) |
diff --git a/src/cachestorefiles.h b/src/cachestorefiles.h index 1906b13..c2cf091 100644 --- a/src/cachestorefiles.h +++ b/src/cachestorefiles.h | |||
| @@ -83,7 +83,7 @@ namespace Bu | |||
| 83 | } | 83 | } |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | virtual void unload( obtype *pObj, const keytype &key ) | 86 | virtual void unload( obtype *pObj, const keytype & ) |
| 87 | { | 87 | { |
| 88 | delete pObj; | 88 | delete pObj; |
| 89 | } | 89 | } |
diff --git a/src/cachestoremyriad.h b/src/cachestoremyriad.h index b90793d..21c84e6 100644 --- a/src/cachestoremyriad.h +++ b/src/cachestoremyriad.h | |||
| @@ -85,7 +85,7 @@ namespace Bu | |||
| 85 | return pOb; | 85 | return pOb; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | virtual void unload( obtype *pObj, const keytype &key ) | 88 | virtual void unload( obtype *pObj, const keytype & ) |
| 89 | { | 89 | { |
| 90 | delete pObj; | 90 | delete pObj; |
| 91 | } | 91 | } |
diff --git a/src/client.cpp b/src/client.cpp index becd1bd..b635c8b 100644 --- a/src/client.cpp +++ b/src/client.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include "bu/client.h" | 8 | #include "bu/client.h" |
| 9 | #include "bu/socket.h" | 9 | #include "bu/tcpsocket.h" |
| 10 | #include <stdlib.h> | 10 | #include <stdlib.h> |
| 11 | #include <errno.h> | 11 | #include <errno.h> |
| 12 | #include "bu/protocol.h" | 12 | #include "bu/protocol.h" |
| @@ -16,7 +16,8 @@ | |||
| 16 | /** Read buffer size. */ | 16 | /** Read buffer size. */ |
| 17 | #define RBS (1024*2) | 17 | #define RBS (1024*2) |
| 18 | 18 | ||
| 19 | Bu::Client::Client( Bu::Socket *pSocket, class Bu::ClientLinkFactory *pfLink ) : | 19 | Bu::Client::Client( Bu::TcpSocket *pSocket, |
| 20 | class Bu::ClientLinkFactory *pfLink ) : | ||
| 20 | pTopStream( pSocket ), | 21 | pTopStream( pSocket ), |
| 21 | pSocket( pSocket ), | 22 | pSocket( pSocket ), |
| 22 | pProto( NULL ), | 23 | pProto( NULL ), |
| @@ -59,7 +60,7 @@ void Bu::Client::processInput() | |||
| 59 | break; | 60 | break; |
| 60 | } | 61 | } |
| 61 | } | 62 | } |
| 62 | catch( Bu::SocketException &e ) | 63 | catch( Bu::TcpSocketException &e ) |
| 63 | { | 64 | { |
| 64 | pTopStream->close(); | 65 | pTopStream->close(); |
| 65 | bWantsDisconnect = true; | 66 | bWantsDisconnect = true; |
| @@ -195,7 +196,7 @@ long Bu::Client::getOutputSize() | |||
| 195 | return qbWrite.getSize(); | 196 | return qbWrite.getSize(); |
| 196 | } | 197 | } |
| 197 | 198 | ||
| 198 | const Bu::Socket *Bu::Client::getSocket() const | 199 | const Bu::TcpSocket *Bu::Client::getSocket() const |
| 199 | { | 200 | { |
| 200 | return pSocket; | 201 | return pSocket; |
| 201 | } | 202 | } |
diff --git a/src/client.h b/src/client.h index f336524..096df2f 100644 --- a/src/client.h +++ b/src/client.h | |||
| @@ -17,7 +17,7 @@ namespace Bu | |||
| 17 | { | 17 | { |
| 18 | class Protocol; | 18 | class Protocol; |
| 19 | class Stream; | 19 | class Stream; |
| 20 | class Socket; | 20 | class TcpSocket; |
| 21 | class ClientLinkFactory; | 21 | class ClientLinkFactory; |
| 22 | 22 | ||
| 23 | /** | 23 | /** |
| @@ -26,7 +26,7 @@ namespace Bu | |||
| 26 | class Client : public Bu::Stream | 26 | class Client : public Bu::Stream |
| 27 | { | 27 | { |
| 28 | public: | 28 | public: |
| 29 | Client( Bu::Socket *pSocket, Bu::ClientLinkFactory *pfLink ); | 29 | Client( Bu::TcpSocket *pSocket, Bu::ClientLinkFactory *pfLink ); |
| 30 | virtual ~Client(); | 30 | virtual ~Client(); |
| 31 | 31 | ||
| 32 | void processInput(); | 32 | void processInput(); |
| @@ -58,7 +58,7 @@ namespace Bu | |||
| 58 | void close(); | 58 | void close(); |
| 59 | void tick(); | 59 | void tick(); |
| 60 | 60 | ||
| 61 | const Bu::Socket *getSocket() const; | 61 | const Bu::TcpSocket *getSocket() const; |
| 62 | 62 | ||
| 63 | void disconnect(); | 63 | void disconnect(); |
| 64 | bool wantsDisconnect(); | 64 | bool wantsDisconnect(); |
| @@ -117,7 +117,7 @@ namespace Bu | |||
| 117 | typedef Bu::List<Bu::Stream *> FilterList; | 117 | typedef Bu::List<Bu::Stream *> FilterList; |
| 118 | FilterList lFilts; | 118 | FilterList lFilts; |
| 119 | Bu::Stream *pTopStream; | 119 | Bu::Stream *pTopStream; |
| 120 | Bu::Socket *pSocket; | 120 | Bu::TcpSocket *pSocket; |
| 121 | Bu::Protocol *pProto; | 121 | Bu::Protocol *pProto; |
| 122 | Bu::QueueBuf qbRead; | 122 | Bu::QueueBuf qbRead; |
| 123 | Bu::QueueBuf qbWrite; | 123 | Bu::QueueBuf qbWrite; |
diff --git a/src/fastcgi.cpp b/src/fastcgi.cpp index 8168928..ca3010e 100644 --- a/src/fastcgi.cpp +++ b/src/fastcgi.cpp | |||
| @@ -24,14 +24,14 @@ Bu::FastCgi::FastCgi() : | |||
| 24 | pSrv( NULL ), | 24 | pSrv( NULL ), |
| 25 | bRunning( true ) | 25 | bRunning( true ) |
| 26 | { | 26 | { |
| 27 | pSrv = new Bu::ServerSocket( STDIN_FILENO, false ); | 27 | pSrv = new Bu::TcpServerSocket( STDIN_FILENO, false ); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | Bu::FastCgi::FastCgi( int iPort ) : | 30 | Bu::FastCgi::FastCgi( int iPort ) : |
| 31 | pSrv( NULL ), | 31 | pSrv( NULL ), |
| 32 | bRunning( true ) | 32 | bRunning( true ) |
| 33 | { | 33 | { |
| 34 | pSrv = new Bu::ServerSocket( iPort ); | 34 | pSrv = new Bu::TcpServerSocket( iPort ); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | Bu::FastCgi::~FastCgi() | 37 | Bu::FastCgi::~FastCgi() |
| @@ -64,17 +64,17 @@ bool Bu::FastCgi::isEmbedded() | |||
| 64 | #endif | 64 | #endif |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::Record &r ) | 67 | void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::Record &r ) |
| 68 | { | 68 | { |
| 69 | int iRead = s.read( &r, sizeof(Record) ); | 69 | int iRead = s.read( &r, sizeof(Record) ); |
| 70 | if( iRead != sizeof(Record) ) | 70 | if( iRead != sizeof(Record) ) |
| 71 | throw Bu::SocketException("Hey, the size %d is wrong for Record. (%s)", | 71 | throw Bu::TcpSocketException("Hey, the size %d is wrong for Record. (%s)", |
| 72 | iRead, strerror( errno ) ); | 72 | iRead, strerror( errno ) ); |
| 73 | r.uRequestId = ntohs( r.uRequestId ); | 73 | r.uRequestId = ntohs( r.uRequestId ); |
| 74 | r.uContentLength = ntohs( r.uContentLength ); | 74 | r.uContentLength = ntohs( r.uContentLength ); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r ) | 77 | void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::Record r ) |
| 78 | { | 78 | { |
| 79 | // sio << "Out -> " << r << sio.nl; | 79 | // sio << "Out -> " << r << sio.nl; |
| 80 | r.uRequestId = htons( r.uRequestId ); | 80 | r.uRequestId = htons( r.uRequestId ); |
| @@ -82,19 +82,19 @@ void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r ) | |||
| 82 | s.write( &r, sizeof(Record) ); | 82 | s.write( &r, sizeof(Record) ); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::BeginRequestBody &b ) | 85 | void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::BeginRequestBody &b ) |
| 86 | { | 86 | { |
| 87 | s.read( &b, sizeof(BeginRequestBody) ); | 87 | s.read( &b, sizeof(BeginRequestBody) ); |
| 88 | b.uRole = ntohs( b.uRole ); | 88 | b.uRole = ntohs( b.uRole ); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::EndRequestBody b ) | 91 | void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::EndRequestBody b ) |
| 92 | { | 92 | { |
| 93 | b.uStatus = htonl( b.uStatus ); | 93 | b.uStatus = htonl( b.uStatus ); |
| 94 | s.write( &b, sizeof(b) ); | 94 | s.write( &b, sizeof(b) ); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead ) | 97 | uint32_t Bu::FastCgi::readLen( Bu::TcpSocket &s, uint16_t &uRead ) |
| 98 | { | 98 | { |
| 99 | uint8_t uByte[4]; | 99 | uint8_t uByte[4]; |
| 100 | s.read( uByte, 1 ); | 100 | s.read( uByte, 1 ); |
| @@ -107,7 +107,7 @@ uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead ) | |||
| 107 | return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]); | 107 | return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | void Bu::FastCgi::readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uRead ) | 110 | void Bu::FastCgi::readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uRead ) |
| 111 | { | 111 | { |
| 112 | uint32_t uName = readLen( s, uRead ); | 112 | uint32_t uName = readLen( s, uRead ); |
| 113 | uint32_t uValue = readLen( s, uRead ); | 113 | uint32_t uValue = readLen( s, uRead ); |
| @@ -162,7 +162,7 @@ void Bu::FastCgi::run() | |||
| 162 | if( iSock < 0 ) | 162 | if( iSock < 0 ) |
| 163 | continue; | 163 | continue; |
| 164 | 164 | ||
| 165 | Bu::Socket s( iSock ); | 165 | Bu::TcpSocket s( iSock ); |
| 166 | s.setBlocking( true ); | 166 | s.setBlocking( true ); |
| 167 | // sio << "Got connection, blocking? " << s.isBlocking() << sio.nl; | 167 | // sio << "Got connection, blocking? " << s.isBlocking() << sio.nl; |
| 168 | try | 168 | try |
| @@ -362,7 +362,7 @@ void Bu::FastCgi::run() | |||
| 362 | } | 362 | } |
| 363 | } | 363 | } |
| 364 | } | 364 | } |
| 365 | catch( Bu::SocketException &e ) | 365 | catch( Bu::TcpSocketException &e ) |
| 366 | { | 366 | { |
| 367 | // sio << "Bu::SocketException: " << e.what() << sio.nl << | 367 | // sio << "Bu::SocketException: " << e.what() << sio.nl << |
| 368 | // "\tSocket open: " << s.isOpen() << sio.nl; | 368 | // "\tSocket open: " << s.isOpen() << sio.nl; |
diff --git a/src/fastcgi.h b/src/fastcgi.h index 262872c..7c1c04c 100644 --- a/src/fastcgi.h +++ b/src/fastcgi.h | |||
| @@ -11,8 +11,8 @@ | |||
| 11 | #include "bu/fstring.h" | 11 | #include "bu/fstring.h" |
| 12 | #include "bu/hash.h" | 12 | #include "bu/hash.h" |
| 13 | #include "bu/array.h" | 13 | #include "bu/array.h" |
| 14 | #include "bu/socket.h" | 14 | #include "bu/tcpsocket.h" |
| 15 | #include "bu/serversocket.h" | 15 | #include "bu/tcpserversocket.h" |
| 16 | 16 | ||
| 17 | namespace Bu | 17 | namespace Bu |
| 18 | { | 18 | { |
| @@ -109,18 +109,18 @@ namespace Bu | |||
| 109 | virtual void onUninit() { }; | 109 | virtual void onUninit() { }; |
| 110 | 110 | ||
| 111 | private: | 111 | private: |
| 112 | void read( Bu::Socket &s, Record &r ); | 112 | void read( Bu::TcpSocket &s, Record &r ); |
| 113 | void read( Bu::Socket &s, BeginRequestBody &b ); | 113 | void read( Bu::TcpSocket &s, BeginRequestBody &b ); |
| 114 | uint32_t readLen( Bu::Socket &s, uint16_t &uUsed ); | 114 | uint32_t readLen( Bu::TcpSocket &s, uint16_t &uUsed ); |
| 115 | void readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uUsed ); | 115 | void readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uUsed ); |
| 116 | 116 | ||
| 117 | void write( Bu::Socket &s, Record r ); | 117 | void write( Bu::TcpSocket &s, Record r ); |
| 118 | void write( Bu::Socket &s, EndRequestBody b ); | 118 | void write( Bu::TcpSocket &s, EndRequestBody b ); |
| 119 | 119 | ||
| 120 | bool hasChannel( int iChan ); | 120 | bool hasChannel( int iChan ); |
| 121 | 121 | ||
| 122 | private: | 122 | private: |
| 123 | Bu::ServerSocket *pSrv; | 123 | Bu::TcpServerSocket *pSrv; |
| 124 | bool bRunning; | 124 | bool bRunning; |
| 125 | Bu::Array<Channel *> aChannel; | 125 | Bu::Array<Channel *> aChannel; |
| 126 | }; | 126 | }; |
diff --git a/src/fbasicstring.h b/src/fbasicstring.h index 4c33479..064ff16 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | 25 | ||
| 26 | namespace Bu | 26 | namespace Bu |
| 27 | { | 27 | { |
| 28 | /** @cond DEVEL */ | ||
| 28 | template< typename chr > | 29 | template< typename chr > |
| 29 | struct FStringChunk | 30 | struct FStringChunk |
| 30 | { | 31 | { |
| @@ -34,10 +35,55 @@ namespace Bu | |||
| 34 | }; | 35 | }; |
| 35 | 36 | ||
| 36 | #define cpy( dest, src, size ) Bu::memcpy( dest, src, size*sizeof(chr) ) | 37 | #define cpy( dest, src, size ) Bu::memcpy( dest, src, size*sizeof(chr) ) |
| 38 | |||
| 39 | template< typename chr, int nMinSize, typename chralloc, | ||
| 40 | typename chunkalloc> class FBasicString; | ||
| 41 | |||
| 42 | template<typename chr> | ||
| 43 | size_t strlen( const chr *pData ) | ||
| 44 | { | ||
| 45 | for( size_t tLen = 0;; ++tLen ) | ||
| 46 | { | ||
| 47 | if( pData[tLen] == (chr)0 ) | ||
| 48 | return tLen; | ||
| 49 | } | ||
| 50 | return -1; | ||
| 51 | } | ||
| 52 | |||
| 53 | template<char> | ||
| 54 | size_t strlen( const char *pData ) | ||
| 55 | { | ||
| 56 | return ::strlen( pData ); | ||
| 57 | } | ||
| 58 | |||
| 59 | template<typename chr> | ||
| 60 | int strncmp( const chr *a, const chr *b, size_t iLen ) | ||
| 61 | { | ||
| 62 | for( size_t iPos = 0; iPos < iLen; iPos++ ) | ||
| 63 | { | ||
| 64 | if( a[iPos] != b[iPos] ) | ||
| 65 | { | ||
| 66 | return a[iPos]-b[iPos]; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | template<char> | ||
| 73 | int strncmp( const char *a, const char *b, size_t iLen ) | ||
| 74 | { | ||
| 75 | return ::strncmp( a, b, iLen ); | ||
| 76 | } | ||
| 37 | 77 | ||
| 38 | template<typename chr, int nMinSize, typename chralloc, typename chunkalloc> | 78 | template<typename chr, int nMinSize, typename chralloc, typename chunkalloc> |
| 39 | struct FStringCore | 79 | struct FStringCore |
| 40 | { | 80 | { |
| 81 | friend class FBasicString<chr, nMinSize, chralloc, chunkalloc>; | ||
| 82 | friend class SharedCore< | ||
| 83 | FBasicString<chr, nMinSize, chralloc, chunkalloc>, | ||
| 84 | FStringCore<chr, nMinSize, chralloc, chunkalloc> | ||
| 85 | >; | ||
| 86 | private: | ||
| 41 | typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> MyType; | 87 | typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> MyType; |
| 42 | typedef struct FStringChunk<chr> Chunk; | 88 | typedef struct FStringChunk<chr> Chunk; |
| 43 | FStringCore() : | 89 | FStringCore() : |
| @@ -157,6 +203,7 @@ namespace Bu | |||
| 157 | nLength += pNewChunk->nLength; | 203 | nLength += pNewChunk->nLength; |
| 158 | } | 204 | } |
| 159 | }; | 205 | }; |
| 206 | /** @endcond */ | ||
| 160 | 207 | ||
| 161 | /** | 208 | /** |
| 162 | * Flexible String class. This class was designed with string passing and | 209 | * Flexible String class. This class was designed with string passing and |
| @@ -174,55 +221,24 @@ namespace Bu | |||
| 174 | *@param chralloc (typename) Memory Allocator for chr | 221 | *@param chralloc (typename) Memory Allocator for chr |
| 175 | *@param chunkalloc (typename) Memory Allocator for chr chunks | 222 | *@param chunkalloc (typename) Memory Allocator for chr chunks |
| 176 | */ | 223 | */ |
| 177 | template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > > | 224 | template< typename chr, int nMinSize=256, |
| 178 | class FBasicString : public SharedCore< FStringCore<chr, nMinSize, chralloc, chunkalloc> > | 225 | typename chralloc=std::allocator<chr>, |
| 226 | typename chunkalloc=std::allocator<struct FStringChunk<chr> > > | ||
| 227 | class FBasicString : public SharedCore< | ||
| 228 | FBasicString<chr, nMinSize, chralloc, chunkalloc>, | ||
| 229 | FStringCore<chr, nMinSize, chralloc, chunkalloc> > | ||
| 179 | { | 230 | { |
| 180 | protected: | 231 | protected: |
| 181 | typedef struct FStringChunk<chr> Chunk; | 232 | typedef struct FStringChunk<chr> Chunk; |
| 182 | typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType; | 233 | typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType; |
| 183 | typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> Core; | 234 | typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> Core; |
| 184 | 235 | ||
| 185 | using SharedCore< Core >::core; | 236 | using SharedCore<MyType, Core >::core; |
| 186 | using SharedCore< Core >::_hardCopy; | 237 | using SharedCore<MyType, Core >::_hardCopy; |
| 187 | |||
| 188 | public: | ||
| 189 | FBasicString() | ||
| 190 | { | ||
| 191 | } | ||
| 192 | |||
| 193 | FBasicString( const chr *pData ) | ||
| 194 | { | ||
| 195 | append( pData ); | ||
| 196 | } | ||
| 197 | |||
| 198 | FBasicString( const chr *pData, long nLength ) | ||
| 199 | { | ||
| 200 | append( pData, nLength ); | ||
| 201 | } | ||
| 202 | 238 | ||
| 203 | FBasicString( const MyType &rSrc ) : | 239 | public: // Iterators |
| 204 | SharedCore<Core>( rSrc ) | ||
| 205 | { | ||
| 206 | } | ||
| 207 | |||
| 208 | FBasicString( const MyType &rSrc, long nLength ) | ||
| 209 | { | ||
| 210 | append( rSrc, nLength ); | ||
| 211 | } | ||
| 212 | |||
| 213 | FBasicString( const MyType &rSrc, long nStart, long nLength ) | ||
| 214 | { | ||
| 215 | append( rSrc, nStart, nLength ); | ||
| 216 | } | ||
| 217 | |||
| 218 | FBasicString( long nSize ) | ||
| 219 | { | ||
| 220 | core->pFirst = core->pLast = core->newChunk( nSize ); | ||
| 221 | core->nLength = nSize; | ||
| 222 | } | ||
| 223 | |||
| 224 | struct iterator; | 240 | struct iterator; |
| 225 | struct const_iterator | 241 | typedef struct const_iterator |
| 226 | { | 242 | { |
| 227 | friend class FBasicString<chr, nMinSize, chralloc, chunkalloc>; | 243 | friend class FBasicString<chr, nMinSize, chralloc, chunkalloc>; |
| 228 | friend struct iterator; | 244 | friend struct iterator; |
| @@ -243,7 +259,7 @@ namespace Bu | |||
| 243 | { | 259 | { |
| 244 | } | 260 | } |
| 245 | 261 | ||
| 246 | const_iterator( const iterator &i ) : | 262 | const_iterator( const struct iterator &i ) : |
| 247 | pChunk( i.pChunk ), | 263 | pChunk( i.pChunk ), |
| 248 | iPos( i.iPos ) | 264 | iPos( i.iPos ) |
| 249 | { | 265 | { |
| @@ -454,7 +470,7 @@ namespace Bu | |||
| 454 | } | 470 | } |
| 455 | return const_iterator( NULL, 0 ); | 471 | return const_iterator( NULL, 0 ); |
| 456 | } | 472 | } |
| 457 | }; | 473 | } const_iterator; |
| 458 | 474 | ||
| 459 | typedef struct iterator | 475 | typedef struct iterator |
| 460 | { | 476 | { |
| @@ -702,11 +718,41 @@ namespace Bu | |||
| 702 | } | 718 | } |
| 703 | } iterator; | 719 | } iterator; |
| 704 | 720 | ||
| 705 | typedef struct const_iterator const_iterator; | 721 | public: |
| 722 | FBasicString() | ||
| 723 | { | ||
| 724 | } | ||
| 725 | |||
| 726 | FBasicString( const chr *pData ) | ||
| 727 | { | ||
| 728 | append( pData ); | ||
| 729 | } | ||
| 730 | |||
| 731 | FBasicString( const chr *pData, long nLength ) | ||
| 732 | { | ||
| 733 | append( pData, nLength ); | ||
| 734 | } | ||
| 735 | |||
| 736 | FBasicString( const MyType &rSrc ) : | ||
| 737 | SharedCore<MyType, Core>( rSrc ) | ||
| 738 | { | ||
| 739 | } | ||
| 706 | 740 | ||
| 707 | //typedef chr *iterator; | 741 | FBasicString( const MyType &rSrc, long nLength ) |
| 708 | // typedef const chr *const_iterator; | 742 | { |
| 709 | // typedef iterator const_iterator; | 743 | append( rSrc, nLength ); |
| 744 | } | ||
| 745 | |||
| 746 | FBasicString( const MyType &rSrc, long nStart, long nLength ) | ||
| 747 | { | ||
| 748 | append( rSrc, nStart, nLength ); | ||
| 749 | } | ||
| 750 | |||
| 751 | FBasicString( long nSize ) | ||
| 752 | { | ||
| 753 | core->pFirst = core->pLast = core->newChunk( nSize ); | ||
| 754 | core->nLength = nSize; | ||
| 755 | } | ||
| 710 | 756 | ||
| 711 | FBasicString( const const_iterator &s ) | 757 | FBasicString( const const_iterator &s ) |
| 712 | { | 758 | { |
| @@ -731,14 +777,8 @@ namespace Bu | |||
| 731 | if( !pData ) return; | 777 | if( !pData ) return; |
| 732 | long nLen; | 778 | long nLen; |
| 733 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { } | 779 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { } |
| 734 | if( nLen == 0 ) | ||
| 735 | return; | ||
| 736 | |||
| 737 | Chunk *pNew = core->newChunk( nLen ); | ||
| 738 | cpy( pNew->pData, pData, nLen ); | ||
| 739 | 780 | ||
| 740 | _hardCopy(); | 781 | append( pData, 0, nLen ); |
| 741 | core->appendChunk( pNew ); | ||
| 742 | } | 782 | } |
| 743 | 783 | ||
| 744 | /** | 784 | /** |
| @@ -748,15 +788,7 @@ namespace Bu | |||
| 748 | */ | 788 | */ |
| 749 | void append( const chr *pData, long nLen ) | 789 | void append( const chr *pData, long nLen ) |
| 750 | { | 790 | { |
| 751 | if( nLen == 0 ) | 791 | append( pData, 0, nLen ); |
| 752 | return; | ||
| 753 | |||
| 754 | Chunk *pNew = core->newChunk( nLen ); | ||
| 755 | |||
| 756 | cpy( pNew->pData, pData, nLen ); | ||
| 757 | |||
| 758 | _hardCopy(); | ||
| 759 | core->appendChunk( pNew ); | ||
| 760 | } | 792 | } |
| 761 | 793 | ||
| 762 | /** | 794 | /** |
| @@ -767,15 +799,37 @@ namespace Bu | |||
| 767 | */ | 799 | */ |
| 768 | void append( const chr *pData, long nStart, long nLen ) | 800 | void append( const chr *pData, long nStart, long nLen ) |
| 769 | { | 801 | { |
| 770 | if( nLen == 0 ) | 802 | if( !pData ) return; |
| 803 | if( nLen <= 0 ) | ||
| 771 | return; | 804 | return; |
| 772 | 805 | ||
| 773 | Chunk *pNew = core->newChunk( nLen ); | 806 | pData += nStart; |
| 774 | |||
| 775 | cpy( pNew->pData, pData+nStart, nLen ); | ||
| 776 | 807 | ||
| 777 | _hardCopy(); | 808 | _hardCopy(); |
| 778 | core->appendChunk( pNew ); | 809 | |
| 810 | if( core->pLast && core->pLast->nLength < nMinSize ) | ||
| 811 | { | ||
| 812 | int nAmnt = nMinSize - core->pLast->nLength; | ||
| 813 | if( nAmnt > nLen ) | ||
| 814 | nAmnt = nLen; | ||
| 815 | cpy( | ||
| 816 | core->pLast->pData+core->pLast->nLength, | ||
| 817 | pData, | ||
| 818 | nAmnt | ||
| 819 | ); | ||
| 820 | pData += nAmnt; | ||
| 821 | core->pLast->nLength += nAmnt; | ||
| 822 | nLen -= nAmnt; | ||
| 823 | core->nLength += nAmnt; | ||
| 824 | } | ||
| 825 | |||
| 826 | if( nLen > 0 ) | ||
| 827 | { | ||
| 828 | Chunk *pNew = core->newChunk( nLen ); | ||
| 829 | cpy( pNew->pData, pData, nLen ); | ||
| 830 | core->appendChunk( pNew ); | ||
| 831 | // core->nLength += nLen; | ||
| 832 | } | ||
| 779 | } | 833 | } |
| 780 | 834 | ||
| 781 | /** | 835 | /** |
| @@ -804,7 +858,7 @@ namespace Bu | |||
| 804 | */ | 858 | */ |
| 805 | void append( const MyType & sData ) | 859 | void append( const MyType & sData ) |
| 806 | { | 860 | { |
| 807 | append( sData.getStr(), sData.getSize() ); | 861 | append( sData.getStr(), 0, sData.getSize() ); |
| 808 | } | 862 | } |
| 809 | 863 | ||
| 810 | /** | 864 | /** |
| @@ -815,7 +869,7 @@ namespace Bu | |||
| 815 | */ | 869 | */ |
| 816 | void append( const MyType & sData, long nLen ) | 870 | void append( const MyType & sData, long nLen ) |
| 817 | { | 871 | { |
| 818 | append( sData.getStr(), nLen ); | 872 | append( sData.getStr(), 0, nLen ); |
| 819 | } | 873 | } |
| 820 | 874 | ||
| 821 | /** | 875 | /** |
| @@ -1029,7 +1083,7 @@ namespace Bu | |||
| 1029 | */ | 1083 | */ |
| 1030 | void insert( long nPos, const chr *pData ) | 1084 | void insert( long nPos, const chr *pData ) |
| 1031 | { | 1085 | { |
| 1032 | insert( nPos, pData, strlen( pData ) ); | 1086 | insert( nPos, pData, Bu::strlen( pData ) ); |
| 1033 | } | 1087 | } |
| 1034 | 1088 | ||
| 1035 | void remove( long nPos, long nLen ) | 1089 | void remove( long nPos, long nLen ) |
| @@ -1155,13 +1209,13 @@ namespace Bu | |||
| 1155 | if( iStart < 0 ) | 1209 | if( iStart < 0 ) |
| 1156 | iStart = 0; | 1210 | iStart = 0; |
| 1157 | if( iStart >= core->nLength ) | 1211 | if( iStart >= core->nLength ) |
| 1158 | return ""; | 1212 | return (const chr[]){(chr)0}; |
| 1159 | if( iSize < 0 ) | 1213 | if( iSize < 0 ) |
| 1160 | iSize = core->nLength; | 1214 | iSize = core->nLength; |
| 1161 | if( iStart+iSize > core->nLength ) | 1215 | if( iStart+iSize > core->nLength ) |
| 1162 | iSize = core->nLength-iStart; | 1216 | iSize = core->nLength-iStart; |
| 1163 | if( iSize == 0 ) | 1217 | if( iSize == 0 ) |
| 1164 | return ""; | 1218 | return (const chr[]){(chr)0}; |
| 1165 | 1219 | ||
| 1166 | flatten(); | 1220 | flatten(); |
| 1167 | MyType ret( core->pFirst->pData+iStart, iSize ); | 1221 | MyType ret( core->pFirst->pData+iStart, iSize ); |
| @@ -1212,37 +1266,6 @@ namespace Bu | |||
| 1212 | } | 1266 | } |
| 1213 | } | 1267 | } |
| 1214 | 1268 | ||
| 1215 | /** | ||
| 1216 | * (std::string compatability) Get a pointer to the string array. | ||
| 1217 | *@returns (chr *) The string data. | ||
| 1218 | */ | ||
| 1219 | DEPRECATED | ||
| 1220 | chr *c_str() | ||
| 1221 | { | ||
| 1222 | if( core->pFirst == NULL || core->nLength == 0 ) | ||
| 1223 | return NULL; | ||
| 1224 | |||
| 1225 | flatten(); | ||
| 1226 | _hardCopy(); | ||
| 1227 | core->pFirst->pData[core->nLength] = (chr)0; | ||
| 1228 | return core->pFirst->pData; | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | /** | ||
| 1232 | * (std::string compatability) Get a const pointer to the string array. | ||
| 1233 | *@returns (const chr *) The string data. | ||
| 1234 | */ | ||
| 1235 | DEPRECATED | ||
| 1236 | const chr *c_str() const | ||
| 1237 | { | ||
| 1238 | if( core->pFirst == NULL || core->nLength == 0 ) | ||
| 1239 | return NULL; | ||
| 1240 | |||
| 1241 | flatten(); | ||
| 1242 | core->pFirst->pData[core->nLength] = (chr)0; | ||
| 1243 | return core->pFirst->pData; | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | Bu::List<MyType> split( const chr c ) const | 1269 | Bu::List<MyType> split( const chr c ) const |
| 1247 | { | 1270 | { |
| 1248 | Bu::List<MyType> ret; | 1271 | Bu::List<MyType> ret; |
| @@ -1423,11 +1446,11 @@ namespace Bu | |||
| 1423 | wordexp_t result; | 1446 | wordexp_t result; |
| 1424 | 1447 | ||
| 1425 | /* Expand the string for the program to run. */ | 1448 | /* Expand the string for the program to run. */ |
| 1426 | switch (wordexp (core->pFirst->pData, &result, 0)) | 1449 | switch (wordexp ((char *)core->pFirst->pData, &result, 0)) |
| 1427 | { | 1450 | { |
| 1428 | case 0: /* Successful. */ | 1451 | case 0: /* Successful. */ |
| 1429 | { | 1452 | { |
| 1430 | set( result.we_wordv[0] ); | 1453 | set( (chr *)result.we_wordv[0] ); |
| 1431 | wordfree( &result ); | 1454 | wordfree( &result ); |
| 1432 | return; | 1455 | return; |
| 1433 | } | 1456 | } |
| @@ -1941,7 +1964,7 @@ namespace Bu | |||
| 1941 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); | 1964 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); |
| 1942 | 1965 | ||
| 1943 | Chunk *pNew = core->newChunk( iLen ); | 1966 | Chunk *pNew = core->newChunk( iLen ); |
| 1944 | vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); | 1967 | vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); |
| 1945 | core->appendChunk( pNew ); | 1968 | core->appendChunk( pNew ); |
| 1946 | 1969 | ||
| 1947 | va_end( ap ); | 1970 | va_end( ap ); |
| @@ -1958,7 +1981,7 @@ namespace Bu | |||
| 1958 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); | 1981 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); |
| 1959 | 1982 | ||
| 1960 | Chunk *pNew = core->newChunk( iLen ); | 1983 | Chunk *pNew = core->newChunk( iLen ); |
| 1961 | vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); | 1984 | vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); |
| 1962 | core->appendChunk( pNew ); | 1985 | core->appendChunk( pNew ); |
| 1963 | 1986 | ||
| 1964 | va_end( ap ); | 1987 | va_end( ap ); |
| @@ -1975,7 +1998,7 @@ namespace Bu | |||
| 1975 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); | 1998 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); |
| 1976 | 1999 | ||
| 1977 | Chunk *pNew = core->newChunk( iLen ); | 2000 | Chunk *pNew = core->newChunk( iLen ); |
| 1978 | vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); | 2001 | vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); |
| 1979 | core->prependChunk( pNew ); | 2002 | core->prependChunk( pNew ); |
| 1980 | 2003 | ||
| 1981 | va_end( ap ); | 2004 | va_end( ap ); |
diff --git a/src/file.cpp b/src/file.cpp index 0566ee8..008b88e 100644 --- a/src/file.cpp +++ b/src/file.cpp | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include <sys/stat.h> | 11 | #include <sys/stat.h> |
| 12 | #include <fcntl.h> | 12 | #include <fcntl.h> |
| 13 | #include <unistd.h> | 13 | #include <unistd.h> |
| 14 | #include <stdlib.h> // for mkstemp | ||
| 15 | #include <time.h> | 14 | #include <time.h> |
| 16 | 15 | ||
| 17 | #include "bu/config.h" | 16 | #include "bu/config.h" |
| @@ -12,7 +12,8 @@ | |||
| 12 | #include "bu/exceptionbase.h" | 12 | #include "bu/exceptionbase.h" |
| 13 | #include "bu/list.h" | 13 | #include "bu/list.h" |
| 14 | #include "bu/util.h" | 14 | #include "bu/util.h" |
| 15 | #include "archivebase.h" | 15 | #include "bu/archivebase.h" |
| 16 | #include "bu/sharedcore.h" | ||
| 16 | 17 | ||
| 17 | #define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) | 18 | #define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) |
| 18 | 19 | ||
| @@ -49,138 +50,357 @@ namespace Bu | |||
| 49 | } | 50 | } |
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 52 | template<typename key, typename value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<value>, typename challoc = std::allocator<uint32_t> > | 53 | template<typename key, typename value, typename sizecalc, typename keyalloc, |
| 54 | typename valuealloc, typename challoc> | ||
| 53 | class Hash; | 55 | class Hash; |
| 54 | 56 | ||
| 55 | template< typename key, typename _value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<_value>, typename challoc = std::allocator<uint32_t> > | 57 | /** @cond DEVEL */ |
| 56 | struct HashProxy | 58 | template<typename key, typename value, typename sizecalc, typename keyalloc, |
| 59 | typename valuealloc, typename challoc > | ||
| 60 | class HashCore | ||
| 57 | { | 61 | { |
| 58 | friend class Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc>; | 62 | friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>; |
| 63 | friend class SharedCore< | ||
| 64 | Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>, | ||
| 65 | HashCore<key, value, sizecalc, keyalloc, valuealloc, challoc> | ||
| 66 | >; | ||
| 59 | private: | 67 | private: |
| 60 | HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, const key *k, uint32_t nPos, uint32_t hash ) : | 68 | HashCore() : |
| 61 | hsh( h ), | 69 | nCapacity( 0 ), |
| 62 | pKey( k ), | 70 | nFilled( 0 ), |
| 63 | nPos( nPos ), | 71 | nDeleted( 0 ), |
| 64 | hash( hash ), | 72 | bFilled( NULL ), |
| 65 | bFilled( false ) | 73 | bDeleted( NULL ), |
| 74 | aKeys( NULL ), | ||
| 75 | aValues( NULL ), | ||
| 76 | aHashCodes( NULL ) | ||
| 66 | { | 77 | { |
| 67 | } | 78 | } |
| 68 | 79 | ||
| 69 | HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, uint32_t nPos, _value *pValue ) : | 80 | virtual ~HashCore() |
| 70 | hsh( h ), | ||
| 71 | nPos( nPos ), | ||
| 72 | pValue( pValue ), | ||
| 73 | bFilled( true ) | ||
| 74 | { | 81 | { |
| 82 | clear(); | ||
| 75 | } | 83 | } |
| 76 | 84 | ||
| 77 | Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &hsh; | 85 | void init() |
| 78 | const key *pKey; | 86 | { |
| 79 | uint32_t nPos; | 87 | if( nCapacity > 0 ) |
| 80 | _value *pValue; | 88 | return; |
| 81 | uint32_t hash; | ||
| 82 | bool bFilled; | ||
| 83 | 89 | ||
| 84 | public: | 90 | nCapacity = 11; |
| 85 | /** | 91 | nKeysSize = bitsToBytes( nCapacity ); |
| 86 | * Cast operator for HashProxy. | 92 | bFilled = ca.allocate( nKeysSize ); |
| 87 | *@returns (value_type &) The value the HashProxy is pointing to. | 93 | bDeleted = ca.allocate( nKeysSize ); |
| 88 | */ | 94 | clearBits(); |
| 89 | operator _value &() | 95 | |
| 96 | aHashCodes = ca.allocate( nCapacity ); | ||
| 97 | aKeys = ka.allocate( nCapacity ); | ||
| 98 | aValues = va.allocate( nCapacity ); | ||
| 99 | } | ||
| 100 | |||
| 101 | void clearBits() | ||
| 90 | { | 102 | { |
| 91 | if( bFilled == false ) | 103 | if( nCapacity == 0 ) |
| 92 | throw HashException( | 104 | return; |
| 93 | excodeNotFilled, | 105 | |
| 94 | "No data assosiated with that key." | 106 | for( uint32_t j = 0; j < nKeysSize; j++ ) |
| 95 | ); | 107 | { |
| 96 | return *pValue; | 108 | bFilled[j] = bDeleted[j] = 0; |
| 109 | } | ||
| 97 | } | 110 | } |
| 98 | 111 | ||
| 99 | /** | 112 | void fill( uint32_t loc, const key &k, const value &v, uint32_t hash ) |
| 100 | * Direct function for retrieving a value out of the HashProxy. | ||
| 101 | *@returns (value_type &) The value pointed to by this HashProxy. | ||
| 102 | */ | ||
| 103 | DEPRECATED | ||
| 104 | _value &value() | ||
| 105 | { | 113 | { |
| 106 | if( bFilled == false ) | 114 | init(); |
| 107 | throw HashException( | 115 | |
| 108 | excodeNotFilled, | 116 | bFilled[loc/32] |= (1<<(loc%32)); |
| 109 | "No data assosiated with that key." | 117 | va.construct( &aValues[loc], v ); |
| 110 | ); | 118 | ka.construct( &aKeys[loc], k ); |
| 111 | return *pValue; | 119 | aHashCodes[loc] = hash; |
| 120 | nFilled++; | ||
| 121 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
| 122 | // nFilled, nDeleted, nCapacity ); | ||
| 123 | } | ||
| 124 | |||
| 125 | void _erase( uint32_t loc ) | ||
| 126 | { | ||
| 127 | if( nCapacity == 0 ) | ||
| 128 | return; | ||
| 129 | |||
| 130 | bDeleted[loc/32] |= (1<<(loc%32)); | ||
| 131 | va.destroy( &aValues[loc] ); | ||
| 132 | ka.destroy( &aKeys[loc] ); | ||
| 133 | nDeleted++; | ||
| 134 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
| 135 | // nFilled, nDeleted, nCapacity ); | ||
| 136 | } | ||
| 137 | |||
| 138 | key &getKeyAtPos( uint32_t nPos ) | ||
| 139 | { | ||
| 140 | if( nPos >= nCapacity ) | ||
| 141 | throw HashException("Referenced position invalid."); | ||
| 142 | return aKeys[nPos]; | ||
| 112 | } | 143 | } |
| 113 | 144 | ||
| 114 | /** | 145 | const key &getKeyAtPos( uint32_t nPos ) const |
| 115 | * Direct function for retrieving a value out of the HashProxy. | ||
| 116 | *@returns (value_type &) The value pointed to by this HashProxy. | ||
| 117 | */ | ||
| 118 | _value &getValue() | ||
| 119 | { | 146 | { |
| 120 | if( bFilled == false ) | 147 | if( nPos >= nCapacity ) |
| 121 | throw HashException( | 148 | throw HashException("Referenced position invalid."); |
| 122 | excodeNotFilled, | 149 | return aKeys[nPos]; |
| 123 | "No data assosiated with that key." | 150 | } |
| 124 | ); | 151 | |
| 125 | return *pValue; | 152 | value &getValueAtPos( uint32_t nPos ) |
| 153 | { | ||
| 154 | if( nPos >= nCapacity ) | ||
| 155 | throw HashException("Referenced position invalid."); | ||
| 156 | return aValues[nPos]; | ||
| 157 | } | ||
| 158 | |||
| 159 | const value &getValueAtPos( uint32_t nPos ) const | ||
| 160 | { | ||
| 161 | if( nPos >= nCapacity ) | ||
| 162 | throw HashException("Referenced position invalid."); | ||
| 163 | return aValues[nPos]; | ||
| 126 | } | 164 | } |
| 127 | 165 | ||
| 128 | /** | 166 | uint32_t getFirstPos( bool &bFinished ) const |
| 129 | * Whether this HashProxy points to something real or not. | 167 | { |
| 130 | */ | 168 | for( uint32_t j = 0; j < nCapacity; j++ ) |
| 131 | bool isFilled() | 169 | { |
| 170 | if( isFilled( j ) ) | ||
| 171 | if( !isDeleted( j ) ) | ||
| 172 | return j; | ||
| 173 | } | ||
| 174 | |||
| 175 | bFinished = true; | ||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const | ||
| 132 | { | 180 | { |
| 133 | return bFilled; | 181 | for( uint32_t j = nPos+1; j < nCapacity; j++ ) |
| 182 | { | ||
| 183 | if( isFilled( j ) ) | ||
| 184 | if( !isDeleted( j ) ) | ||
| 185 | return j; | ||
| 186 | } | ||
| 187 | |||
| 188 | bFinished = true; | ||
| 189 | return 0; | ||
| 134 | } | 190 | } |
| 135 | 191 | ||
| 136 | /** | 192 | uint32_t probe( uint32_t hash, const key &k, bool &bFill, bool rehash=true ) |
| 137 | * Erase the data pointed to by this HashProxy. | ||
| 138 | */ | ||
| 139 | void erase() | ||
| 140 | { | 193 | { |
| 141 | if( bFilled ) | 194 | init(); |
| 195 | |||
| 196 | uint32_t nCur = hash%nCapacity; | ||
| 197 | |||
| 198 | // First we scan to see if the key is already there, abort if we | ||
| 199 | // run out of probing room, or we find a non-filled entry | ||
| 200 | int8_t j; | ||
| 201 | for( j = 0; | ||
| 202 | isFilled( nCur ) && j < 32; | ||
| 203 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
| 204 | ) | ||
| 205 | { | ||
| 206 | // Is this the same hash code we were looking for? | ||
| 207 | if( hash == aHashCodes[nCur] ) | ||
| 208 | { | ||
| 209 | // Skip over deleted entries. Deleted entries are also filled, | ||
| 210 | // so we only have to do this check here. | ||
| 211 | if( isDeleted( nCur ) ) | ||
| 212 | continue; | ||
| 213 | |||
| 214 | // Is it really the same key? (for safety) | ||
| 215 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
| 216 | { | ||
| 217 | bFill = true; | ||
| 218 | return nCur; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | // This is our insurance, if the table is full, then go ahead and | ||
| 224 | // rehash, then try again. | ||
| 225 | if( (isFilled( nCur ) || j == 32) && rehash == true ) | ||
| 142 | { | 226 | { |
| 143 | hsh._erase( nPos ); | 227 | reHash( szCalc( nCapacity, nFilled, nDeleted ) ); |
| 144 | hsh.onDelete(); | 228 | |
| 229 | // This is potentially dangerous, and could cause an infinite loop. | ||
| 230 | // Be careful writing probe, eh? | ||
| 231 | return probe( hash, k, bFill ); | ||
| 145 | } | 232 | } |
| 233 | |||
| 234 | bFill = false; | ||
| 235 | return nCur; | ||
| 146 | } | 236 | } |
| 237 | |||
| 238 | uint32_t probe( uint32_t hash, key k, bool &bFill ) const | ||
| 239 | { | ||
| 240 | if( nCapacity == 0 ) | ||
| 241 | throw Bu::ExceptionBase("Probe in empty hash table."); | ||
| 147 | 242 | ||
| 148 | /** | 243 | uint32_t nCur = hash%nCapacity; |
| 149 | * Assign data to this point in the hash table. | 244 | |
| 150 | *@param nval (value_type) the data to assign. | 245 | // First we scan to see if the key is already there, abort if we |
| 151 | */ | 246 | // run out of probing room, or we find a non-filled entry |
| 152 | _value operator=( _value nval ) | 247 | for( int8_t j = 0; |
| 248 | isFilled( nCur ) && j < 32; | ||
| 249 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
| 250 | ) | ||
| 251 | { | ||
| 252 | // Is this the same hash code we were looking for? | ||
| 253 | if( hash == aHashCodes[nCur] ) | ||
| 254 | { | ||
| 255 | // Skip over deleted entries. Deleted entries are also filled, | ||
| 256 | // so we only have to do this check here. | ||
| 257 | if( isDeleted( nCur ) ) | ||
| 258 | continue; | ||
| 259 | |||
| 260 | // Is it really the same key? (for safety) | ||
| 261 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
| 262 | { | ||
| 263 | bFill = true; | ||
| 264 | return nCur; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | bFill = false; | ||
| 270 | return nCur; | ||
| 271 | } | ||
| 272 | |||
| 273 | void insert( const key &k, const value &v ) | ||
| 153 | { | 274 | { |
| 154 | if( bFilled ) | 275 | uint32_t hash = __calcHashCode( k ); |
| 276 | bool bFill; | ||
| 277 | uint32_t nPos = probe( hash, k, bFill ); | ||
| 278 | |||
| 279 | if( bFill ) | ||
| 155 | { | 280 | { |
| 156 | hsh.va.destroy( &hsh.aValues[nPos] ); | 281 | va.destroy( &aValues[nPos] ); |
| 157 | hsh.va.construct( &hsh.aValues[nPos], nval ); | 282 | va.construct( &aValues[nPos], v ); |
| 158 | hsh.onUpdate(); | ||
| 159 | } | 283 | } |
| 160 | else | 284 | else |
| 161 | { | 285 | { |
| 162 | hsh.fill( nPos, *pKey, nval, hash ); | 286 | fill( nPos, k, v, hash ); |
| 163 | hsh.onInsert(); | 287 | } |
| 288 | } | ||
| 289 | |||
| 290 | void reHash( uint32_t nNewSize ) | ||
| 291 | { | ||
| 292 | //printf("---REHASH---"); | ||
| 293 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
| 294 | // nFilled, nDeleted, nCapacity ); | ||
| 295 | |||
| 296 | // Save all the old data | ||
| 297 | uint32_t nOldCapacity = nCapacity; | ||
| 298 | uint32_t *bOldFilled = bFilled; | ||
| 299 | uint32_t *aOldHashCodes = aHashCodes; | ||
| 300 | uint32_t nOldKeysSize = nKeysSize; | ||
| 301 | uint32_t *bOldDeleted = bDeleted; | ||
| 302 | value *aOldValues = aValues; | ||
| 303 | key *aOldKeys = aKeys; | ||
| 304 | |||
| 305 | // Calculate new sizes | ||
| 306 | nCapacity = nNewSize; | ||
| 307 | nKeysSize = bitsToBytes( nCapacity ); | ||
| 308 | |||
| 309 | // Allocate new memory + prep | ||
| 310 | bFilled = ca.allocate( nKeysSize ); | ||
| 311 | bDeleted = ca.allocate( nKeysSize ); | ||
| 312 | clearBits(); | ||
| 313 | |||
| 314 | aHashCodes = ca.allocate( nCapacity ); | ||
| 315 | aKeys = ka.allocate( nCapacity ); | ||
| 316 | aValues = va.allocate( nCapacity ); | ||
| 317 | |||
| 318 | nDeleted = nFilled = 0; | ||
| 319 | |||
| 320 | // Re-insert all of the old data (except deleted items) | ||
| 321 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
| 322 | { | ||
| 323 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | ||
| 324 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
| 325 | { | ||
| 326 | insert( aOldKeys[j], aOldValues[j] ); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | // Delete all of the old data | ||
| 331 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
| 332 | { | ||
| 333 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | ||
| 334 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
| 335 | { | ||
| 336 | va.destroy( &aOldValues[j] ); | ||
| 337 | ka.destroy( &aOldKeys[j] ); | ||
| 338 | } | ||
| 164 | } | 339 | } |
| 340 | va.deallocate( aOldValues, nOldCapacity ); | ||
| 341 | ka.deallocate( aOldKeys, nOldCapacity ); | ||
| 342 | ca.deallocate( bOldFilled, nOldKeysSize ); | ||
| 343 | ca.deallocate( bOldDeleted, nOldKeysSize ); | ||
| 344 | ca.deallocate( aOldHashCodes, nOldCapacity ); | ||
| 345 | } | ||
| 165 | 346 | ||
| 166 | return nval; | 347 | bool isFilled( uint32_t loc ) const |
| 348 | { | ||
| 349 | if( loc >= nCapacity ) | ||
| 350 | throw HashException("Referenced position invalid."); | ||
| 351 | return (bFilled[loc/32]&(1<<(loc%32)))!=0; | ||
| 167 | } | 352 | } |
| 168 | 353 | ||
| 169 | /** | 354 | bool isDeleted( uint32_t loc ) const |
| 170 | * Pointer extraction operator. Access to members of data pointed to | ||
| 171 | * by HashProxy. | ||
| 172 | *@returns (value_type *) | ||
| 173 | */ | ||
| 174 | _value *operator->() | ||
| 175 | { | 355 | { |
| 176 | if( bFilled == false ) | 356 | if( loc >= nCapacity ) |
| 177 | throw HashException( | 357 | throw HashException("Referenced position invalid."); |
| 178 | excodeNotFilled, | 358 | return (bDeleted[loc/32]&(1<<(loc%32)))!=0; |
| 179 | "No data assosiated with that key." | 359 | } |
| 180 | ); | 360 | |
| 181 | return pValue; | 361 | void clear() |
| 362 | { | ||
| 363 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
| 364 | { | ||
| 365 | if( isFilled( j ) ) | ||
| 366 | if( !isDeleted( j ) ) | ||
| 367 | { | ||
| 368 | va.destroy( &aValues[j] ); | ||
| 369 | ka.destroy( &aKeys[j] ); | ||
| 370 | } | ||
| 371 | } | ||
| 372 | va.deallocate( aValues, nCapacity ); | ||
| 373 | ka.deallocate( aKeys, nCapacity ); | ||
| 374 | ca.deallocate( bFilled, nKeysSize ); | ||
| 375 | ca.deallocate( bDeleted, nKeysSize ); | ||
| 376 | ca.deallocate( aHashCodes, nCapacity ); | ||
| 377 | |||
| 378 | bFilled = NULL; | ||
| 379 | bDeleted = NULL; | ||
| 380 | aKeys = NULL; | ||
| 381 | aValues = NULL; | ||
| 382 | aHashCodes = NULL; | ||
| 383 | |||
| 384 | nCapacity = 0; | ||
| 385 | nFilled = 0; | ||
| 386 | nDeleted = 0; | ||
| 182 | } | 387 | } |
| 388 | |||
| 389 | uint32_t nCapacity; | ||
| 390 | uint32_t nFilled; | ||
| 391 | uint32_t nDeleted; | ||
| 392 | uint32_t *bFilled; | ||
| 393 | uint32_t *bDeleted; | ||
| 394 | uint32_t nKeysSize; | ||
| 395 | key *aKeys; | ||
| 396 | value *aValues; | ||
| 397 | uint32_t *aHashCodes; | ||
| 398 | valuealloc va; | ||
| 399 | keyalloc ka; | ||
| 400 | challoc ca; | ||
| 401 | sizecalc szCalc; | ||
| 183 | }; | 402 | }; |
| 403 | /** @endcond */ | ||
| 184 | 404 | ||
| 185 | /** | 405 | /** |
| 186 | * Libbu++ Template Hash Table. This is your average hash table, that uses | 406 | * Libbu++ Template Hash Table. This is your average hash table, that uses |
| @@ -224,119 +444,38 @@ namespace Bu | |||
| 224 | *@param challoc (typename) Byte allocator for bitflags | 444 | *@param challoc (typename) Byte allocator for bitflags |
| 225 | *@ingroup Containers | 445 | *@ingroup Containers |
| 226 | */ | 446 | */ |
| 227 | template<typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc > | 447 | template<typename key, typename value, |
| 228 | class Hash | 448 | typename sizecalc = __calcNextTSize_fast, |
| 449 | typename keyalloc = std::allocator<key>, | ||
| 450 | typename valuealloc = std::allocator<value>, | ||
| 451 | typename challoc = std::allocator<uint32_t> | ||
| 452 | > | ||
| 453 | class Hash : public SharedCore< | ||
| 454 | Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>, | ||
| 455 | HashCore<key, value, sizecalc, keyalloc, valuealloc, challoc> | ||
| 456 | > | ||
| 229 | { | 457 | { |
| 230 | friend struct HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>; | 458 | private: |
| 459 | typedef class HashCore<key, value, sizecalc, keyalloc, valuealloc, challoc> Core; | ||
| 231 | typedef class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> MyType; | 460 | typedef class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> MyType; |
| 461 | protected: | ||
| 462 | using SharedCore<MyType, Core>::core; | ||
| 463 | using SharedCore<MyType, Core>::_hardCopy; | ||
| 464 | using SharedCore<MyType, Core>::_resetCore; | ||
| 465 | using SharedCore<MyType, Core>::_allocateCore; | ||
| 466 | |||
| 232 | public: | 467 | public: |
| 233 | Hash() : | 468 | Hash() |
| 234 | nCapacity( 11 ), | ||
| 235 | nFilled( 0 ), | ||
| 236 | nDeleted( 0 ), | ||
| 237 | bFilled( NULL ), | ||
| 238 | bDeleted( NULL ), | ||
| 239 | aKeys( NULL ), | ||
| 240 | aValues( NULL ), | ||
| 241 | aHashCodes( NULL ) | ||
| 242 | { | ||
| 243 | nKeysSize = bitsToBytes( nCapacity ); | ||
| 244 | bFilled = ca.allocate( nKeysSize ); | ||
| 245 | bDeleted = ca.allocate( nKeysSize ); | ||
| 246 | clearBits(); | ||
| 247 | |||
| 248 | aHashCodes = ca.allocate( nCapacity ); | ||
| 249 | aKeys = ka.allocate( nCapacity ); | ||
| 250 | aValues = va.allocate( nCapacity ); | ||
| 251 | } | ||
| 252 | |||
| 253 | Hash( const Hash &src ) : | ||
| 254 | nCapacity( src.nCapacity ), | ||
| 255 | nFilled( 0 ), | ||
| 256 | nDeleted( 0 ), | ||
| 257 | bFilled( NULL ), | ||
| 258 | bDeleted( NULL ), | ||
| 259 | aKeys( NULL ), | ||
| 260 | aValues( NULL ), | ||
| 261 | aHashCodes( NULL ) | ||
| 262 | { | 469 | { |
| 263 | nKeysSize = bitsToBytes( nCapacity ); | ||
| 264 | bFilled = ca.allocate( nKeysSize ); | ||
| 265 | bDeleted = ca.allocate( nKeysSize ); | ||
| 266 | clearBits(); | ||
| 267 | |||
| 268 | aHashCodes = ca.allocate( nCapacity ); | ||
| 269 | aKeys = ka.allocate( nCapacity ); | ||
| 270 | aValues = va.allocate( nCapacity ); | ||
| 271 | |||
| 272 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
| 273 | { | ||
| 274 | if( src.isFilled( j ) && !src.isDeleted( j ) ) | ||
| 275 | { | ||
| 276 | insert( src.aKeys[j], src.aValues[j] ); | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | 470 | } |
| 280 | 471 | ||
| 281 | /** | 472 | Hash( const MyType &src ) : |
| 282 | * Hashtable assignment operator. Clears this hashtable and | 473 | SharedCore<MyType, Core >( src ) |
| 283 | * copies RH into it. | ||
| 284 | */ | ||
| 285 | Hash &operator=( const Hash &src ) | ||
| 286 | { | 474 | { |
| 287 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
| 288 | { | ||
| 289 | if( isFilled( j ) && !isDeleted( j ) ) | ||
| 290 | { | ||
| 291 | va.destroy( &aValues[j] ); | ||
| 292 | ka.destroy( &aKeys[j] ); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | va.deallocate( aValues, nCapacity ); | ||
| 296 | ka.deallocate( aKeys, nCapacity ); | ||
| 297 | ca.deallocate( bFilled, nKeysSize ); | ||
| 298 | ca.deallocate( bDeleted, nKeysSize ); | ||
| 299 | ca.deallocate( aHashCodes, nCapacity ); | ||
| 300 | |||
| 301 | nFilled = 0; | ||
| 302 | nDeleted = 0; | ||
| 303 | nCapacity = src.nCapacity; | ||
| 304 | nKeysSize = bitsToBytes( nCapacity ); | ||
| 305 | bFilled = ca.allocate( nKeysSize ); | ||
| 306 | bDeleted = ca.allocate( nKeysSize ); | ||
| 307 | clearBits(); | ||
| 308 | |||
| 309 | aHashCodes = ca.allocate( nCapacity ); | ||
| 310 | aKeys = ka.allocate( nCapacity ); | ||
| 311 | aValues = va.allocate( nCapacity ); | ||
| 312 | |||
| 313 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
| 314 | { | ||
| 315 | if( src.isFilled( j ) && !src.isDeleted( j ) ) | ||
| 316 | { | ||
| 317 | insert( src.aKeys[j], src.aValues[j] ); | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | return *this; | ||
| 322 | } | 475 | } |
| 323 | 476 | ||
| 324 | virtual ~Hash() | 477 | virtual ~Hash() |
| 325 | { | 478 | { |
| 326 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
| 327 | { | ||
| 328 | if( isFilled( j ) ) | ||
| 329 | if( !isDeleted( j ) ) | ||
| 330 | { | ||
| 331 | va.destroy( &aValues[j] ); | ||
| 332 | ka.destroy( &aKeys[j] ); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | va.deallocate( aValues, nCapacity ); | ||
| 336 | ka.deallocate( aKeys, nCapacity ); | ||
| 337 | ca.deallocate( bFilled, nKeysSize ); | ||
| 338 | ca.deallocate( bDeleted, nKeysSize ); | ||
| 339 | ca.deallocate( aHashCodes, nCapacity ); | ||
| 340 | } | 479 | } |
| 341 | 480 | ||
| 342 | /** | 481 | /** |
| @@ -345,7 +484,7 @@ namespace Bu | |||
| 345 | */ | 484 | */ |
| 346 | uint32_t getCapacity() const | 485 | uint32_t getCapacity() const |
| 347 | { | 486 | { |
| 348 | return nCapacity; | 487 | return core->nCapacity; |
| 349 | } | 488 | } |
| 350 | 489 | ||
| 351 | /** | 490 | /** |
| @@ -355,7 +494,7 @@ namespace Bu | |||
| 355 | */ | 494 | */ |
| 356 | uint32_t getFill() const | 495 | uint32_t getFill() const |
| 357 | { | 496 | { |
| 358 | return nFilled; | 497 | return core->nFilled; |
| 359 | } | 498 | } |
| 360 | 499 | ||
| 361 | /** | 500 | /** |
| @@ -364,12 +503,12 @@ namespace Bu | |||
| 364 | */ | 503 | */ |
| 365 | uint32_t getSize() const | 504 | uint32_t getSize() const |
| 366 | { | 505 | { |
| 367 | return nFilled-nDeleted; | 506 | return core->nFilled-core->nDeleted; |
| 368 | } | 507 | } |
| 369 | 508 | ||
| 370 | bool isEmpty() const | 509 | bool isEmpty() const |
| 371 | { | 510 | { |
| 372 | return (nFilled-nDeleted) == 0; | 511 | return (core->nFilled-core->nDeleted) == 0; |
| 373 | } | 512 | } |
| 374 | 513 | ||
| 375 | /** | 514 | /** |
| @@ -379,27 +518,140 @@ namespace Bu | |||
| 379 | */ | 518 | */ |
| 380 | uint32_t getDeleted() const | 519 | uint32_t getDeleted() const |
| 381 | { | 520 | { |
| 382 | return nDeleted; | 521 | return core->nDeleted; |
| 383 | } | 522 | } |
| 384 | 523 | ||
| 524 | struct HashProxy | ||
| 525 | { | ||
| 526 | friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>; | ||
| 527 | private: | ||
| 528 | HashProxy( MyType &h, const key *k, uint32_t nPos, uint32_t hash ) : | ||
| 529 | hsh( h ), | ||
| 530 | pKey( k ), | ||
| 531 | nPos( nPos ), | ||
| 532 | hash( hash ), | ||
| 533 | bFilled( false ) | ||
| 534 | { | ||
| 535 | } | ||
| 536 | |||
| 537 | HashProxy( MyType &h, uint32_t nPos, value *pValue ) : | ||
| 538 | hsh( h ), | ||
| 539 | nPos( nPos ), | ||
| 540 | pValue( pValue ), | ||
| 541 | bFilled( true ) | ||
| 542 | { | ||
| 543 | } | ||
| 544 | |||
| 545 | MyType &hsh; | ||
| 546 | const key *pKey; | ||
| 547 | uint32_t nPos; | ||
| 548 | value *pValue; | ||
| 549 | uint32_t hash; | ||
| 550 | bool bFilled; | ||
| 551 | |||
| 552 | public: | ||
| 553 | /** | ||
| 554 | * Cast operator for HashProxy. | ||
| 555 | *@returns (value_type &) The value the HashProxy is pointing to. | ||
| 556 | */ | ||
| 557 | operator value &() | ||
| 558 | { | ||
| 559 | if( bFilled == false ) | ||
| 560 | throw HashException( | ||
| 561 | excodeNotFilled, | ||
| 562 | "No data assosiated with that key." | ||
| 563 | ); | ||
| 564 | return *pValue; | ||
| 565 | } | ||
| 566 | |||
| 567 | /** | ||
| 568 | * Direct function for retrieving a value out of the HashProxy. | ||
| 569 | *@returns (value_type &) The value pointed to by this HashProxy. | ||
| 570 | */ | ||
| 571 | value &getValue() | ||
| 572 | { | ||
| 573 | if( bFilled == false ) | ||
| 574 | throw HashException( | ||
| 575 | excodeNotFilled, | ||
| 576 | "No data assosiated with that key." | ||
| 577 | ); | ||
| 578 | return *pValue; | ||
| 579 | } | ||
| 580 | |||
| 581 | /** | ||
| 582 | * Whether this HashProxy points to something real or not. | ||
| 583 | */ | ||
| 584 | bool isFilled() | ||
| 585 | { | ||
| 586 | return bFilled; | ||
| 587 | } | ||
| 588 | |||
| 589 | /** | ||
| 590 | * Erase the data pointed to by this HashProxy. | ||
| 591 | */ | ||
| 592 | void erase() | ||
| 593 | { | ||
| 594 | if( bFilled ) | ||
| 595 | { | ||
| 596 | hsh.core->_erase( nPos ); | ||
| 597 | } | ||
| 598 | } | ||
| 599 | |||
| 600 | /** | ||
| 601 | * Assign data to this point in the hash table. | ||
| 602 | *@param nval (value_type) the data to assign. | ||
| 603 | */ | ||
| 604 | value operator=( value nval ) | ||
| 605 | { | ||
| 606 | if( bFilled ) | ||
| 607 | { | ||
| 608 | hsh.core->va.destroy( &hsh.core->aValues[nPos] ); | ||
| 609 | hsh.core->va.construct( &hsh.core->aValues[nPos], nval ); | ||
| 610 | } | ||
| 611 | else | ||
| 612 | { | ||
| 613 | hsh.core->fill( nPos, *pKey, nval, hash ); | ||
| 614 | } | ||
| 615 | |||
| 616 | return nval; | ||
| 617 | } | ||
| 618 | |||
| 619 | /** | ||
| 620 | * Pointer extraction operator. Access to members of data pointed to | ||
| 621 | * by HashProxy. | ||
| 622 | *@returns (value_type *) | ||
| 623 | */ | ||
| 624 | value *operator->() | ||
| 625 | { | ||
| 626 | if( bFilled == false ) | ||
| 627 | throw HashException( | ||
| 628 | excodeNotFilled, | ||
| 629 | "No data assosiated with that key." | ||
| 630 | ); | ||
| 631 | return pValue; | ||
| 632 | } | ||
| 633 | }; | ||
| 634 | |||
| 385 | /** | 635 | /** |
| 386 | * Hash table index operator | 636 | * Hash table index operator |
| 387 | *@param k (key_type) Key of data to be retrieved. | 637 | *@param k (key_type) Key of data to be retrieved. |
| 388 | *@returns (HashProxy) Proxy pointing to the data. | 638 | *@returns (HashProxy) Proxy pointing to the data. |
| 389 | */ | 639 | */ |
| 390 | virtual HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc> operator[]( const key &k ) | 640 | HashProxy operator[]( const key &k ) |
| 391 | { | 641 | { |
| 642 | _hardCopy(); | ||
| 643 | |||
| 392 | uint32_t hash = __calcHashCode( k ); | 644 | uint32_t hash = __calcHashCode( k ); |
| 393 | bool bFill; | 645 | bool bFill; |
| 394 | uint32_t nPos = probe( hash, k, bFill ); | 646 | uint32_t nPos = core->probe( hash, k, bFill ); |
| 395 | 647 | ||
| 396 | if( bFill ) | 648 | if( bFill ) |
| 397 | { | 649 | { |
| 398 | return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, nPos, &aValues[nPos] ); | 650 | return HashProxy( *this, nPos, &core->aValues[nPos] ); |
| 399 | } | 651 | } |
| 400 | else | 652 | else |
| 401 | { | 653 | { |
| 402 | return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, &k, nPos, hash ); | 654 | return HashProxy( *this, &k, nPos, hash ); |
| 403 | } | 655 | } |
| 404 | } | 656 | } |
| 405 | 657 | ||
| @@ -408,39 +660,28 @@ namespace Bu | |||
| 408 | *@param k (key_type) Key to list the value under. | 660 | *@param k (key_type) Key to list the value under. |
| 409 | *@param v (value_type) Value to store in the hash table. | 661 | *@param v (value_type) Value to store in the hash table. |
| 410 | */ | 662 | */ |
| 411 | virtual void insert( const key &k, const value &v ) | 663 | void insert( const key &k, const value &v ) |
| 412 | { | 664 | { |
| 413 | uint32_t hash = __calcHashCode( k ); | 665 | _hardCopy(); |
| 414 | bool bFill; | ||
| 415 | uint32_t nPos = probe( hash, k, bFill ); | ||
| 416 | 666 | ||
| 417 | if( bFill ) | 667 | core->insert( k, v ); |
| 418 | { | ||
| 419 | va.destroy( &aValues[nPos] ); | ||
| 420 | va.construct( &aValues[nPos], v ); | ||
| 421 | onUpdate(); | ||
| 422 | } | ||
| 423 | else | ||
| 424 | { | ||
| 425 | fill( nPos, k, v, hash ); | ||
| 426 | onInsert(); | ||
| 427 | } | ||
| 428 | } | 668 | } |
| 429 | 669 | ||
| 430 | /** | 670 | /** |
| 431 | * Remove a value from the hash table. | 671 | * Remove a value from the hash table. |
| 432 | *@param k (key_type) The data under this key will be erased. | 672 | *@param k (key_type) The data under this key will be erased. |
| 433 | */ | 673 | */ |
| 434 | virtual void erase( const key &k ) | 674 | void erase( const key &k ) |
| 435 | { | 675 | { |
| 676 | _hardCopy(); | ||
| 677 | |||
| 436 | uint32_t hash = __calcHashCode( k ); | 678 | uint32_t hash = __calcHashCode( k ); |
| 437 | bool bFill; | 679 | bool bFill; |
| 438 | uint32_t nPos = probe( hash, k, bFill ); | 680 | uint32_t nPos = core->probe( hash, k, bFill ); |
| 439 | 681 | ||
| 440 | if( bFill ) | 682 | if( bFill ) |
| 441 | { | 683 | { |
| 442 | _erase( nPos ); | 684 | core->_erase( nPos ); |
| 443 | onDelete(); | ||
| 444 | } | 685 | } |
| 445 | } | 686 | } |
| 446 | 687 | ||
| @@ -450,14 +691,16 @@ namespace Bu | |||
| 450 | * Remove a value from the hash pointed to from an iterator. | 691 | * Remove a value from the hash pointed to from an iterator. |
| 451 | *@param i (iterator &) The data to be erased. | 692 | *@param i (iterator &) The data to be erased. |
| 452 | */ | 693 | */ |
| 453 | virtual void erase( struct iterator &i ) | 694 | void erase( struct iterator &i ) |
| 454 | { | 695 | { |
| 455 | if( this != i.hsh ) | 696 | if( this != i.hsh ) |
| 456 | throw HashException("This iterator didn't come from this Hash."); | 697 | throw HashException("This iterator didn't come from this Hash."); |
| 457 | if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) | 698 | |
| 699 | _hardCopy(); | ||
| 700 | |||
| 701 | if( core->isFilled( i.nPos ) && !core->isDeleted( i.nPos ) ) | ||
| 458 | { | 702 | { |
| 459 | _erase( i.nPos ); | 703 | core->_erase( i.nPos ); |
| 460 | onDelete(); | ||
| 461 | } | 704 | } |
| 462 | } | 705 | } |
| 463 | 706 | ||
| @@ -466,17 +709,7 @@ namespace Bu | |||
| 466 | */ | 709 | */ |
| 467 | virtual void clear() | 710 | virtual void clear() |
| 468 | { | 711 | { |
| 469 | for( uint32_t j = 0; j < nCapacity; j++ ) | 712 | _resetCore(); |
| 470 | { | ||
| 471 | if( isFilled( j ) ) | ||
| 472 | if( !isDeleted( j ) ) | ||
| 473 | { | ||
| 474 | _erase( j ); | ||
| 475 | onDelete(); | ||
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | clearBits(); | ||
| 480 | } | 713 | } |
| 481 | 714 | ||
| 482 | /** | 715 | /** |
| @@ -484,15 +717,17 @@ namespace Bu | |||
| 484 | *@param k (key_type) Key pointing to the data to be retrieved. | 717 | *@param k (key_type) Key pointing to the data to be retrieved. |
| 485 | *@returns (value_type &) The data pointed to by (k). | 718 | *@returns (value_type &) The data pointed to by (k). |
| 486 | */ | 719 | */ |
| 487 | virtual value &get( const key &k ) | 720 | value &get( const key &k ) |
| 488 | { | 721 | { |
| 722 | _hardCopy(); | ||
| 723 | |||
| 489 | uint32_t hash = __calcHashCode( k ); | 724 | uint32_t hash = __calcHashCode( k ); |
| 490 | bool bFill; | 725 | bool bFill; |
| 491 | uint32_t nPos = probe( hash, k, bFill, false ); | 726 | uint32_t nPos = core->probe( hash, k, bFill, false ); |
| 492 | 727 | ||
| 493 | if( bFill ) | 728 | if( bFill ) |
| 494 | { | 729 | { |
| 495 | return aValues[nPos]; | 730 | return core->aValues[nPos]; |
| 496 | } | 731 | } |
| 497 | else | 732 | else |
| 498 | { | 733 | { |
| @@ -509,15 +744,15 @@ namespace Bu | |||
| 509 | *@returns (const value_type &) A const version of the data pointed | 744 | *@returns (const value_type &) A const version of the data pointed |
| 510 | * to by (k). | 745 | * to by (k). |
| 511 | */ | 746 | */ |
| 512 | virtual const value &get( const key &k ) const | 747 | const value &get( const key &k ) const |
| 513 | { | 748 | { |
| 514 | uint32_t hash = __calcHashCode( k ); | 749 | uint32_t hash = __calcHashCode( k ); |
| 515 | bool bFill; | 750 | bool bFill; |
| 516 | uint32_t nPos = probe( hash, k, bFill ); | 751 | uint32_t nPos = core->probe( hash, k, bFill ); |
| 517 | 752 | ||
| 518 | if( bFill ) | 753 | if( bFill ) |
| 519 | { | 754 | { |
| 520 | return aValues[nPos]; | 755 | return core->aValues[nPos]; |
| 521 | } | 756 | } |
| 522 | else | 757 | else |
| 523 | { | 758 | { |
| @@ -533,18 +768,10 @@ namespace Bu | |||
| 533 | *@param k (key_type) The key to check. | 768 | *@param k (key_type) The key to check. |
| 534 | *@returns (bool) Whether there was an item in the hash under key (k). | 769 | *@returns (bool) Whether there was an item in the hash under key (k). |
| 535 | */ | 770 | */ |
| 536 | virtual bool has( const key &k ) | 771 | bool has( const key &k ) const |
| 537 | { | 772 | { |
| 538 | bool bFill; | 773 | bool bFill; |
| 539 | probe( __calcHashCode( k ), k, bFill, false ); | 774 | core->probe( __calcHashCode( k ), k, bFill ); |
| 540 | |||
| 541 | return bFill; | ||
| 542 | } | ||
| 543 | |||
| 544 | virtual bool has( const key &k ) const | ||
| 545 | { | ||
| 546 | bool bFill; | ||
| 547 | probe( __calcHashCode( k ), k, bFill ); | ||
| 548 | 775 | ||
| 549 | return bFill; | 776 | return bFill; |
| 550 | } | 777 | } |
| @@ -561,7 +788,7 @@ namespace Bu | |||
| 561 | nPos( 0 ), | 788 | nPos( 0 ), |
| 562 | bFinished( false ) | 789 | bFinished( false ) |
| 563 | { | 790 | { |
| 564 | nPos = hsh->getFirstPos( bFinished ); | 791 | nPos = hsh->core->getFirstPos( bFinished ); |
| 565 | } | 792 | } |
| 566 | 793 | ||
| 567 | iterator( MyType *hsh, bool bDone ) : | 794 | iterator( MyType *hsh, bool bDone ) : |
| @@ -590,11 +817,6 @@ namespace Bu | |||
| 590 | { | 817 | { |
| 591 | } | 818 | } |
| 592 | 819 | ||
| 593 | DEPRECATED bool isActive() const | ||
| 594 | { | ||
| 595 | return !bFinished; | ||
| 596 | } | ||
| 597 | |||
| 598 | bool isValid() const | 820 | bool isValid() const |
| 599 | { | 821 | { |
| 600 | return !bFinished; | 822 | return !bFinished; |
| @@ -611,7 +833,7 @@ namespace Bu | |||
| 611 | iterator operator++( int ) | 833 | iterator operator++( int ) |
| 612 | { | 834 | { |
| 613 | if( bFinished == false ) | 835 | if( bFinished == false ) |
| 614 | nPos = hsh->getNextPos( nPos, bFinished ); | 836 | nPos = hsh->core->getNextPos( nPos, bFinished ); |
| 615 | 837 | ||
| 616 | return *this; | 838 | return *this; |
| 617 | } | 839 | } |
| @@ -622,7 +844,7 @@ namespace Bu | |||
| 622 | iterator operator++() | 844 | iterator operator++() |
| 623 | { | 845 | { |
| 624 | if( bFinished == false ) | 846 | if( bFinished == false ) |
| 625 | nPos = hsh->getNextPos( nPos, bFinished ); | 847 | nPos = hsh->core->getNextPos( nPos, bFinished ); |
| 626 | 848 | ||
| 627 | return *this; | 849 | return *this; |
| 628 | } | 850 | } |
| @@ -671,21 +893,22 @@ namespace Bu | |||
| 671 | */ | 893 | */ |
| 672 | value &operator *() | 894 | value &operator *() |
| 673 | { | 895 | { |
| 674 | return hsh->getValueAtPos( nPos ); | 896 | hsh->_hardCopy(); |
| 897 | return hsh->core->getValueAtPos( nPos ); | ||
| 675 | } | 898 | } |
| 676 | 899 | ||
| 677 | const value &operator *() const | 900 | const value &operator *() const |
| 678 | { | 901 | { |
| 679 | return hsh->getValueAtPos( nPos ); | 902 | return hsh->core->getValueAtPos( nPos ); |
| 680 | } | 903 | } |
| 681 | 904 | ||
| 682 | /** | 905 | /** |
| 683 | * Get the key behind this iterator. | 906 | * Get the key behind this iterator. |
| 684 | *@returns (key_type &) The key behind this iterator. | 907 | *@returns (key_type &) The key behind this iterator. |
| 685 | */ | 908 | */ |
| 686 | key &getKey() | 909 | const key &getKey() const |
| 687 | { | 910 | { |
| 688 | return hsh->getKeyAtPos( nPos ); | 911 | return hsh->core->getKeyAtPos( nPos ); |
| 689 | } | 912 | } |
| 690 | 913 | ||
| 691 | /** | 914 | /** |
| @@ -694,7 +917,17 @@ namespace Bu | |||
| 694 | */ | 917 | */ |
| 695 | value &getValue() | 918 | value &getValue() |
| 696 | { | 919 | { |
| 697 | return hsh->getValueAtPos( nPos ); | 920 | hsh->_hardCopy(); |
| 921 | return hsh->core->getValueAtPos( nPos ); | ||
| 922 | } | ||
| 923 | |||
| 924 | /** | ||
| 925 | * Get the value behind this iterator. | ||
| 926 | *@returns (value_type &) The value behind this iterator. | ||
| 927 | */ | ||
| 928 | const value &getValue() const | ||
| 929 | { | ||
| 930 | return hsh->core->getValueAtPos( nPos ); | ||
| 698 | } | 931 | } |
| 699 | } iterator; | 932 | } iterator; |
| 700 | 933 | ||
| @@ -710,7 +943,7 @@ namespace Bu | |||
| 710 | nPos( 0 ), | 943 | nPos( 0 ), |
| 711 | bFinished( false ) | 944 | bFinished( false ) |
| 712 | { | 945 | { |
| 713 | nPos = hsh->getFirstPos( bFinished ); | 946 | nPos = hsh->core->getFirstPos( bFinished ); |
| 714 | } | 947 | } |
| 715 | 948 | ||
| 716 | const_iterator( const MyType *hsh, bool bDone ) : | 949 | const_iterator( const MyType *hsh, bool bDone ) : |
| @@ -762,7 +995,7 @@ namespace Bu | |||
| 762 | const_iterator operator++( int ) | 995 | const_iterator operator++( int ) |
| 763 | { | 996 | { |
| 764 | if( bFinished == false ) | 997 | if( bFinished == false ) |
| 765 | nPos = hsh->getNextPos( nPos, bFinished ); | 998 | nPos = hsh->core->getNextPos( nPos, bFinished ); |
| 766 | 999 | ||
| 767 | return *this; | 1000 | return *this; |
| 768 | } | 1001 | } |
| @@ -773,7 +1006,7 @@ namespace Bu | |||
| 773 | const_iterator operator++() | 1006 | const_iterator operator++() |
| 774 | { | 1007 | { |
| 775 | if( bFinished == false ) | 1008 | if( bFinished == false ) |
| 776 | nPos = hsh->getNextPos( nPos, bFinished ); | 1009 | nPos = hsh->core->getNextPos( nPos, bFinished ); |
| 777 | 1010 | ||
| 778 | return *this; | 1011 | return *this; |
| 779 | } | 1012 | } |
| @@ -822,7 +1055,7 @@ namespace Bu | |||
| 822 | */ | 1055 | */ |
| 823 | const value &operator *() const | 1056 | const value &operator *() const |
| 824 | { | 1057 | { |
| 825 | return hsh->getValueAtPos( nPos ); | 1058 | return hsh->core->getValueAtPos( nPos ); |
| 826 | } | 1059 | } |
| 827 | 1060 | ||
| 828 | /** | 1061 | /** |
| @@ -831,7 +1064,7 @@ namespace Bu | |||
| 831 | */ | 1064 | */ |
| 832 | const key &getKey() const | 1065 | const key &getKey() const |
| 833 | { | 1066 | { |
| 834 | return hsh->getKeyAtPos( nPos ); | 1067 | return hsh->core->getKeyAtPos( nPos ); |
| 835 | } | 1068 | } |
| 836 | 1069 | ||
| 837 | /** | 1070 | /** |
| @@ -840,7 +1073,7 @@ namespace Bu | |||
| 840 | */ | 1073 | */ |
| 841 | const value &getValue() const | 1074 | const value &getValue() const |
| 842 | { | 1075 | { |
| 843 | return hsh->getValueAtPos( nPos ); | 1076 | return hsh->core->getValueAtPos( nPos ); |
| 844 | } | 1077 | } |
| 845 | } const_iterator; | 1078 | } const_iterator; |
| 846 | 1079 | ||
| @@ -883,13 +1116,13 @@ namespace Bu | |||
| 883 | { | 1116 | { |
| 884 | Bu::List<key> lKeys; | 1117 | Bu::List<key> lKeys; |
| 885 | 1118 | ||
| 886 | for( uint32_t j = 0; j < nCapacity; j++ ) | 1119 | for( uint32_t j = 0; j < core->nCapacity; j++ ) |
| 887 | { | 1120 | { |
| 888 | if( isFilled( j ) ) | 1121 | if( core->isFilled( j ) ) |
| 889 | { | 1122 | { |
| 890 | if( !isDeleted( j ) ) | 1123 | if( !core->isDeleted( j ) ) |
| 891 | { | 1124 | { |
| 892 | lKeys.append( aKeys[j] ); | 1125 | lKeys.append( core->aKeys[j] ); |
| 893 | } | 1126 | } |
| 894 | } | 1127 | } |
| 895 | } | 1128 | } |
| @@ -901,13 +1134,13 @@ namespace Bu | |||
| 901 | { | 1134 | { |
| 902 | Bu::List<value> lValues; | 1135 | Bu::List<value> lValues; |
| 903 | 1136 | ||
| 904 | for( uint32_t j = 0; j < nCapacity; j++ ) | 1137 | for( uint32_t j = 0; j < core->nCapacity; j++ ) |
| 905 | { | 1138 | { |
| 906 | if( isFilled( j ) ) | 1139 | if( core->isFilled( j ) ) |
| 907 | { | 1140 | { |
| 908 | if( !isDeleted( j ) ) | 1141 | if( !core->isDeleted( j ) ) |
| 909 | { | 1142 | { |
| 910 | lValues.append( aValues[j] ); | 1143 | lValues.append( core->aValues[j] ); |
| 911 | } | 1144 | } |
| 912 | } | 1145 | } |
| 913 | } | 1146 | } |
| @@ -915,244 +1148,74 @@ namespace Bu | |||
| 915 | return lValues; | 1148 | return lValues; |
| 916 | } | 1149 | } |
| 917 | 1150 | ||
| 918 | protected: | 1151 | bool operator==( const MyType &rhs ) const |
| 919 | virtual void onInsert() {} | ||
| 920 | virtual void onUpdate() {} | ||
| 921 | virtual void onDelete() {} | ||
| 922 | virtual void onReHash() {} | ||
| 923 | |||
| 924 | virtual void clearBits() | ||
| 925 | { | ||
| 926 | for( uint32_t j = 0; j < nKeysSize; j++ ) | ||
| 927 | { | ||
| 928 | bFilled[j] = bDeleted[j] = 0; | ||
| 929 | } | ||
| 930 | } | ||
| 931 | |||
| 932 | virtual void fill( uint32_t loc, const key &k, const value &v, uint32_t hash ) | ||
| 933 | { | ||
| 934 | bFilled[loc/32] |= (1<<(loc%32)); | ||
| 935 | va.construct( &aValues[loc], v ); | ||
| 936 | ka.construct( &aKeys[loc], k ); | ||
| 937 | aHashCodes[loc] = hash; | ||
| 938 | nFilled++; | ||
| 939 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
| 940 | // nFilled, nDeleted, nCapacity ); | ||
| 941 | } | ||
| 942 | |||
| 943 | virtual void _erase( uint32_t loc ) | ||
| 944 | { | ||
| 945 | bDeleted[loc/32] |= (1<<(loc%32)); | ||
| 946 | va.destroy( &aValues[loc] ); | ||
| 947 | ka.destroy( &aKeys[loc] ); | ||
| 948 | nDeleted++; | ||
| 949 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
| 950 | // nFilled, nDeleted, nCapacity ); | ||
| 951 | } | ||
| 952 | |||
| 953 | virtual key &getKeyAtPos( uint32_t nPos ) | ||
| 954 | { | ||
| 955 | return aKeys[nPos]; | ||
| 956 | } | ||
| 957 | |||
| 958 | virtual const key &getKeyAtPos( uint32_t nPos ) const | ||
| 959 | { | ||
| 960 | return aKeys[nPos]; | ||
| 961 | } | ||
| 962 | |||
| 963 | virtual value &getValueAtPos( uint32_t nPos ) | ||
| 964 | { | ||
| 965 | return aValues[nPos]; | ||
| 966 | } | ||
| 967 | |||
| 968 | virtual const value &getValueAtPos( uint32_t nPos ) const | ||
| 969 | { | ||
| 970 | return aValues[nPos]; | ||
| 971 | } | ||
| 972 | |||
| 973 | virtual uint32_t getFirstPos( bool &bFinished ) const | ||
| 974 | { | ||
| 975 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
| 976 | { | ||
| 977 | if( isFilled( j ) ) | ||
| 978 | if( !isDeleted( j ) ) | ||
| 979 | return j; | ||
| 980 | } | ||
| 981 | |||
| 982 | bFinished = true; | ||
| 983 | return 0; | ||
| 984 | } | ||
| 985 | |||
| 986 | virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const | ||
| 987 | { | 1152 | { |
| 988 | for( uint32_t j = nPos+1; j < nCapacity; j++ ) | 1153 | if( this == &rhs ) |
| 989 | { | 1154 | return true; |
| 990 | if( isFilled( j ) ) | 1155 | if( core == rhs.core ) |
| 991 | if( !isDeleted( j ) ) | 1156 | return true; |
| 992 | return j; | 1157 | if( core == NULL || rhs.core == NULL ) |
| 993 | } | 1158 | return false; |
| 994 | 1159 | if( getSize() != rhs.getSize() ) | |
| 995 | bFinished = true; | 1160 | return false; |
| 996 | return 0; | 1161 | |
| 997 | } | 1162 | for( uint32_t j = 0; j < core->nCapacity; j++ ) |
| 998 | |||
| 999 | uint32_t probe( uint32_t hash, const key &k, bool &bFill, bool rehash=true ) | ||
| 1000 | { | ||
| 1001 | uint32_t nCur = hash%nCapacity; | ||
| 1002 | |||
| 1003 | // First we scan to see if the key is already there, abort if we | ||
| 1004 | // run out of probing room, or we find a non-filled entry | ||
| 1005 | int8_t j; | ||
| 1006 | for( j = 0; | ||
| 1007 | isFilled( nCur ) && j < 32; | ||
| 1008 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
| 1009 | ) | ||
| 1010 | { | 1163 | { |
| 1011 | // Is this the same hash code we were looking for? | 1164 | if( core->isFilled( j ) ) |
| 1012 | if( hash == aHashCodes[nCur] ) | ||
| 1013 | { | 1165 | { |
| 1014 | // Skip over deleted entries. Deleted entries are also filled, | 1166 | if( !core->isDeleted( j ) ) |
| 1015 | // so we only have to do this check here. | ||
| 1016 | if( isDeleted( nCur ) ) | ||
| 1017 | continue; | ||
| 1018 | |||
| 1019 | // Is it really the same key? (for safety) | ||
| 1020 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
| 1021 | { | 1167 | { |
| 1022 | bFill = true; | 1168 | // Check to see if this key is in the other hash |
| 1023 | return nCur; | 1169 | if( rhs.has( core->aKeys[j] ) ) |
| 1170 | { | ||
| 1171 | if( !(core->aValues[j] == rhs.get( core->aKeys[j]) ) ) | ||
| 1172 | { | ||
| 1173 | return false; | ||
| 1174 | } | ||
| 1175 | } | ||
| 1176 | else | ||
| 1177 | { | ||
| 1178 | return false; | ||
| 1179 | } | ||
| 1024 | } | 1180 | } |
| 1025 | } | 1181 | } |
| 1026 | } | 1182 | } |
| 1027 | 1183 | ||
| 1028 | // This is our insurance, if the table is full, then go ahead and | 1184 | return true; |
| 1029 | // rehash, then try again. | ||
| 1030 | if( (isFilled( nCur ) || j == 32) && rehash == true ) | ||
| 1031 | { | ||
| 1032 | reHash( szCalc(getCapacity(), getFill(), getDeleted()) ); | ||
| 1033 | |||
| 1034 | // This is potentially dangerous, and could cause an infinite loop. | ||
| 1035 | // Be careful writing probe, eh? | ||
| 1036 | return probe( hash, k, bFill ); | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | bFill = false; | ||
| 1040 | return nCur; | ||
| 1041 | } | 1185 | } |
| 1042 | |||
| 1043 | uint32_t probe( uint32_t hash, key k, bool &bFill ) const | ||
| 1044 | { | ||
| 1045 | uint32_t nCur = hash%nCapacity; | ||
| 1046 | |||
| 1047 | // First we scan to see if the key is already there, abort if we | ||
| 1048 | // run out of probing room, or we find a non-filled entry | ||
| 1049 | for( int8_t j = 0; | ||
| 1050 | isFilled( nCur ) && j < 32; | ||
| 1051 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
| 1052 | ) | ||
| 1053 | { | ||
| 1054 | // Is this the same hash code we were looking for? | ||
| 1055 | if( hash == aHashCodes[nCur] ) | ||
| 1056 | { | ||
| 1057 | // Skip over deleted entries. Deleted entries are also filled, | ||
| 1058 | // so we only have to do this check here. | ||
| 1059 | if( isDeleted( nCur ) ) | ||
| 1060 | continue; | ||
| 1061 | |||
| 1062 | // Is it really the same key? (for safety) | ||
| 1063 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
| 1064 | { | ||
| 1065 | bFill = true; | ||
| 1066 | return nCur; | ||
| 1067 | } | ||
| 1068 | } | ||
| 1069 | } | ||
| 1070 | 1186 | ||
| 1071 | bFill = false; | 1187 | bool operator!=( const MyType &rhs ) const |
| 1072 | return nCur; | 1188 | { |
| 1189 | return !(*this == rhs); | ||
| 1073 | } | 1190 | } |
| 1074 | 1191 | ||
| 1075 | void reHash( uint32_t nNewSize ) | 1192 | protected: |
| 1193 | virtual Core *_copyCore( Core *src ) | ||
| 1076 | { | 1194 | { |
| 1077 | //printf("---REHASH---"); | 1195 | Core *pRet = _allocateCore(); |
| 1078 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
| 1079 | // nFilled, nDeleted, nCapacity ); | ||
| 1080 | |||
| 1081 | // Save all the old data | ||
| 1082 | uint32_t nOldCapacity = nCapacity; | ||
| 1083 | uint32_t *bOldFilled = bFilled; | ||
| 1084 | uint32_t *aOldHashCodes = aHashCodes; | ||
| 1085 | uint32_t nOldKeysSize = nKeysSize; | ||
| 1086 | uint32_t *bOldDeleted = bDeleted; | ||
| 1087 | value *aOldValues = aValues; | ||
| 1088 | key *aOldKeys = aKeys; | ||
| 1089 | |||
| 1090 | // Calculate new sizes | ||
| 1091 | nCapacity = nNewSize; | ||
| 1092 | nKeysSize = bitsToBytes( nCapacity ); | ||
| 1093 | |||
| 1094 | // Allocate new memory + prep | ||
| 1095 | bFilled = ca.allocate( nKeysSize ); | ||
| 1096 | bDeleted = ca.allocate( nKeysSize ); | ||
| 1097 | clearBits(); | ||
| 1098 | 1196 | ||
| 1099 | aHashCodes = ca.allocate( nCapacity ); | 1197 | pRet->nFilled = 0; |
| 1100 | aKeys = ka.allocate( nCapacity ); | 1198 | pRet->nDeleted = 0; |
| 1101 | aValues = va.allocate( nCapacity ); | 1199 | pRet->nCapacity = src->nCapacity; |
| 1102 | 1200 | pRet->nKeysSize = bitsToBytes( pRet->nCapacity ); | |
| 1103 | nDeleted = nFilled = 0; | 1201 | pRet->bFilled = pRet->ca.allocate( pRet->nKeysSize ); |
| 1202 | pRet->bDeleted = pRet->ca.allocate( pRet->nKeysSize ); | ||
| 1203 | pRet->clearBits(); | ||
| 1104 | 1204 | ||
| 1105 | // Re-insert all of the old data (except deleted items) | 1205 | pRet->aHashCodes = pRet->ca.allocate( pRet->nCapacity ); |
| 1106 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | 1206 | pRet->aKeys = pRet->ka.allocate( pRet->nCapacity ); |
| 1107 | { | 1207 | pRet->aValues = pRet->va.allocate( pRet->nCapacity ); |
| 1108 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | ||
| 1109 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
| 1110 | { | ||
| 1111 | insert( aOldKeys[j], aOldValues[j] ); | ||
| 1112 | } | ||
| 1113 | } | ||
| 1114 | 1208 | ||
| 1115 | // Delete all of the old data | 1209 | for( uint32_t j = 0; j < src->nCapacity; j++ ) |
| 1116 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
| 1117 | { | 1210 | { |
| 1118 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | 1211 | if( src->isFilled( j ) && !src->isDeleted( j ) ) |
| 1119 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
| 1120 | { | 1212 | { |
| 1121 | va.destroy( &aOldValues[j] ); | 1213 | pRet->insert( src->aKeys[j], src->aValues[j] ); |
| 1122 | ka.destroy( &aOldKeys[j] ); | ||
| 1123 | } | 1214 | } |
| 1124 | } | 1215 | } |
| 1125 | va.deallocate( aOldValues, nOldCapacity ); | ||
| 1126 | ka.deallocate( aOldKeys, nOldCapacity ); | ||
| 1127 | ca.deallocate( bOldFilled, nOldKeysSize ); | ||
| 1128 | ca.deallocate( bOldDeleted, nOldKeysSize ); | ||
| 1129 | ca.deallocate( aOldHashCodes, nOldCapacity ); | ||
| 1130 | } | ||
| 1131 | 1216 | ||
| 1132 | virtual bool isFilled( uint32_t loc ) const | 1217 | return pRet; |
| 1133 | { | ||
| 1134 | return (bFilled[loc/32]&(1<<(loc%32)))!=0; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | virtual bool isDeleted( uint32_t loc ) const | ||
| 1138 | { | ||
| 1139 | return (bDeleted[loc/32]&(1<<(loc%32)))!=0; | ||
| 1140 | } | 1218 | } |
| 1141 | |||
| 1142 | protected: | ||
| 1143 | uint32_t nCapacity; | ||
| 1144 | uint32_t nFilled; | ||
| 1145 | uint32_t nDeleted; | ||
| 1146 | uint32_t *bFilled; | ||
| 1147 | uint32_t *bDeleted; | ||
| 1148 | uint32_t nKeysSize; | ||
| 1149 | key *aKeys; | ||
| 1150 | value *aValues; | ||
| 1151 | uint32_t *aHashCodes; | ||
| 1152 | valuealloc va; | ||
| 1153 | keyalloc ka; | ||
| 1154 | challoc ca; | ||
| 1155 | sizecalc szCalc; | ||
| 1156 | }; | 1219 | }; |
| 1157 | 1220 | ||
| 1158 | template<typename T> uint32_t __calcHashCode( const T &k ) | 1221 | template<typename T> uint32_t __calcHashCode( const T &k ) |
| @@ -13,76 +13,93 @@ | |||
| 13 | #include "bu/exceptionbase.h" | 13 | #include "bu/exceptionbase.h" |
| 14 | #include "bu/util.h" | 14 | #include "bu/util.h" |
| 15 | #include "bu/queue.h" | 15 | #include "bu/queue.h" |
| 16 | #include "bu/sharedcore.h" | ||
| 16 | 17 | ||
| 17 | namespace Bu | 18 | namespace Bu |
| 18 | { | 19 | { |
| 19 | subExceptionDecl( HeapException ); | 20 | subExceptionDecl( HeapException ); |
| 20 | 21 | ||
| 21 | /** | 22 | template<typename item, typename cmpfunc, typename itemalloc> |
| 22 | * A priority queue that allows for an unlimited number of priorities. All | 23 | class Heap; |
| 23 | * objects enqueued must support less-than-comparison. Then every time an | 24 | |
| 24 | * item is dequeued it is always the least item in the heap. The heap | 25 | /** @cond DEVEL */ |
| 25 | * operates using a binary tree for storage, which allows most operations | 26 | template<typename item, typename cmpfunc, typename itemalloc> |
| 26 | * to be very fast. Enqueueing and dequeueing are both O(log(N)) operatoins | 27 | class HeapCore |
| 27 | * whereas peeking is constant time. | ||
| 28 | * | ||
| 29 | * This heap implementation allows iterating, however please note that any | ||
| 30 | * enqueue or dequeue operation will invalidate the iterator and make it | ||
| 31 | * unusable (if it still works, you shouldn't trust the results). Also, | ||
| 32 | * the items are not stored in memory in order, they are optomized into a | ||
| 33 | * tree. This means that the items will be in effectively random order | ||
| 34 | * while iterating through them, and the order cannot be trusted. Also, | ||
| 35 | * modifying an item in the heap will not cause that item to be re-sorted. | ||
| 36 | * If you want to change the position of an item in the heap you will have | ||
| 37 | * to dequeue every item before it, dequeue that item, change it, and | ||
| 38 | * re-enqueue all of the items removed. | ||
| 39 | */ | ||
| 40 | template<typename item, typename cmpfunc=__basicLTCmp<item>, typename itemalloc=std::allocator<item> > | ||
| 41 | class Heap : public Queue<item> | ||
| 42 | { | 28 | { |
| 43 | public: | 29 | friend class Heap<item, cmpfunc, itemalloc>; |
| 44 | Heap() : | 30 | friend class SharedCore< |
| 45 | iSize( 7 ), | 31 | Heap<item, cmpfunc, itemalloc>, HeapCore<item, cmpfunc, itemalloc> |
| 32 | >; | ||
| 33 | private: | ||
| 34 | HeapCore() : | ||
| 35 | iSize( 0 ), | ||
| 46 | iFill( 0 ), | 36 | iFill( 0 ), |
| 47 | aItem( ia.allocate( iSize ) ) | 37 | aItem( NULL ) |
| 48 | { | 38 | { |
| 49 | } | 39 | } |
| 50 | 40 | ||
| 51 | Heap( cmpfunc cmpin ) : | 41 | virtual ~HeapCore() |
| 52 | iSize( 7 ), | ||
| 53 | iFill( 0 ), | ||
| 54 | aItem( ia.allocate( iSize ) ), | ||
| 55 | cmp( cmpin ) | ||
| 56 | { | 42 | { |
| 43 | clear(); | ||
| 57 | } | 44 | } |
| 58 | 45 | ||
| 59 | Heap( int iInitialCapacity ) : | 46 | void init() |
| 60 | iSize( 0 ), | ||
| 61 | iFill( 0 ), | ||
| 62 | aItem( NULL ) | ||
| 63 | { | 47 | { |
| 64 | for( iSize = 1; iSize < iInitialCapacity; iSize=iSize*2+1 ) { } | 48 | if( iSize > 0 ) |
| 49 | return; | ||
| 50 | |||
| 51 | iSize = 7; | ||
| 52 | iFill = 0; | ||
| 65 | aItem = ia.allocate( iSize ); | 53 | aItem = ia.allocate( iSize ); |
| 66 | } | 54 | } |
| 67 | 55 | ||
| 68 | Heap( cmpfunc cmpin, int iInitialCapacity ) : | 56 | void init( int iCap ) |
| 69 | iSize( 0 ), | ||
| 70 | iFill( 0 ), | ||
| 71 | aItem( NULL ), | ||
| 72 | cmp( cmpin ) | ||
| 73 | { | 57 | { |
| 74 | for( iSize = 1; iSize < iInitialCapacity; iSize=iSize*2+1 ) { } | 58 | if( iSize > 0 ) |
| 59 | return; | ||
| 60 | |||
| 61 | for( iSize = 1; iSize < iCap; iSize=iSize*2+1 ) { } | ||
| 62 | iFill = 0; | ||
| 75 | aItem = ia.allocate( iSize ); | 63 | aItem = ia.allocate( iSize ); |
| 76 | } | 64 | } |
| 77 | 65 | ||
| 78 | virtual ~Heap() | 66 | void clear() |
| 79 | { | 67 | { |
| 68 | if( iSize == 0 ) | ||
| 69 | return; | ||
| 70 | |||
| 80 | for( int j = 0; j < iFill; j++ ) | 71 | for( int j = 0; j < iFill; j++ ) |
| 81 | ia.destroy( &aItem[j] ); | 72 | ia.destroy( &aItem[j] ); |
| 82 | ia.deallocate( aItem, iSize ); | 73 | ia.deallocate( aItem, iSize ); |
| 83 | aItem = NULL; | 74 | aItem = NULL; |
| 75 | iSize = 0; | ||
| 76 | iFill = 0; | ||
| 84 | } | 77 | } |
| 78 | |||
| 79 | void upSize() | ||
| 80 | { | ||
| 81 | if( iSize == 0 ) | ||
| 82 | { | ||
| 83 | init(); | ||
| 84 | return; | ||
| 85 | } | ||
| 85 | 86 | ||
| 87 | item *aNewItems = ia.allocate( iSize*2+1 ); | ||
| 88 | // | ||
| 89 | // We cannot use a memcopy here because we don't know what kind | ||
| 90 | // of datastructures are being used, we have to copy them one at | ||
| 91 | // a time. | ||
| 92 | // | ||
| 93 | for( int j = 0; j < iFill; j++ ) | ||
| 94 | { | ||
| 95 | ia.construct( &aNewItems[j], aItem[j] ); | ||
| 96 | ia.destroy( &aItem[j] ); | ||
| 97 | } | ||
| 98 | ia.deallocate( aItem, iSize ); | ||
| 99 | aItem = aNewItems; | ||
| 100 | iSize = iSize*2+1; | ||
| 101 | } | ||
| 102 | |||
| 86 | virtual void enqueue( const item &it ) | 103 | virtual void enqueue( const item &it ) |
| 87 | { | 104 | { |
| 88 | item i = it; // TODO: This is a silly workaround, put the i item | 105 | item i = it; // TODO: This is a silly workaround, put the i item |
| @@ -126,20 +143,6 @@ namespace Bu | |||
| 126 | iFill++; | 143 | iFill++; |
| 127 | } | 144 | } |
| 128 | 145 | ||
| 129 | virtual item &peek() | ||
| 130 | { | ||
| 131 | if( iFill == 0 ) | ||
| 132 | throw HeapException("Heap empty."); | ||
| 133 | return aItem[0]; | ||
| 134 | } | ||
| 135 | |||
| 136 | virtual const item &peek() const | ||
| 137 | { | ||
| 138 | if( iFill == 0 ) | ||
| 139 | throw HeapException("Heap empty."); | ||
| 140 | return aItem[0]; | ||
| 141 | } | ||
| 142 | |||
| 143 | virtual item dequeue() | 146 | virtual item dequeue() |
| 144 | { | 147 | { |
| 145 | if( iFill == 0 ) | 148 | if( iFill == 0 ) |
| @@ -174,14 +177,118 @@ namespace Bu | |||
| 174 | return iRet; | 177 | return iRet; |
| 175 | } | 178 | } |
| 176 | 179 | ||
| 180 | private: | ||
| 181 | int iSize; | ||
| 182 | int iFill; | ||
| 183 | item *aItem; | ||
| 184 | cmpfunc cmp; | ||
| 185 | itemalloc ia; | ||
| 186 | }; | ||
| 187 | /** @endcond */ | ||
| 188 | |||
| 189 | /** | ||
| 190 | * A priority queue that allows for an unlimited number of priorities. All | ||
| 191 | * objects enqueued must support less-than-comparison. Then every time an | ||
| 192 | * item is dequeued it is always the least item in the heap. The heap | ||
| 193 | * operates using a binary tree for storage, which allows most operations | ||
| 194 | * to be very fast. Enqueueing and dequeueing are both O(log(N)) operatoins | ||
| 195 | * whereas peeking is constant time. | ||
| 196 | * | ||
| 197 | * This heap implementation allows iterating, however please note that any | ||
| 198 | * enqueue or dequeue operation will invalidate the iterator and make it | ||
| 199 | * unusable (if it still works, you shouldn't trust the results). Also, | ||
| 200 | * the items are not stored in memory in order, they are optomized into a | ||
| 201 | * tree. This means that the items will be in effectively random order | ||
| 202 | * while iterating through them, and the order cannot be trusted. Also, | ||
| 203 | * modifying an item in the heap will not cause that item to be re-sorted. | ||
| 204 | * If you want to change the position of an item in the heap you will have | ||
| 205 | * to dequeue every item before it, dequeue that item, change it, and | ||
| 206 | * re-enqueue all of the items removed. | ||
| 207 | */ | ||
| 208 | template<typename item, typename cmpfunc=__basicLTCmp<item>, typename itemalloc=std::allocator<item> > | ||
| 209 | class Heap : public Queue<item>, public SharedCore< | ||
| 210 | Heap<item, cmpfunc, itemalloc>, | ||
| 211 | HeapCore<item, cmpfunc, itemalloc> | ||
| 212 | > | ||
| 213 | { | ||
| 214 | private: | ||
| 215 | typedef class Heap<item,cmpfunc,itemalloc> MyType; | ||
| 216 | typedef class HeapCore<item,cmpfunc,itemalloc> Core; | ||
| 217 | |||
| 218 | protected: | ||
| 219 | using SharedCore<MyType, Core>::core; | ||
| 220 | using SharedCore<MyType, Core>::_hardCopy; | ||
| 221 | using SharedCore<MyType, Core>::_resetCore; | ||
| 222 | using SharedCore<MyType, Core>::_allocateCore; | ||
| 223 | |||
| 224 | public: | ||
| 225 | Heap() | ||
| 226 | { | ||
| 227 | } | ||
| 228 | |||
| 229 | Heap( cmpfunc cmpin ) | ||
| 230 | { | ||
| 231 | core->cmp = cmpin; | ||
| 232 | } | ||
| 233 | |||
| 234 | Heap( int iInitialCapacity ) | ||
| 235 | { | ||
| 236 | core->init( iInitialCapacity ); | ||
| 237 | } | ||
| 238 | |||
| 239 | Heap( cmpfunc cmpin, int iInitialCapacity ) | ||
| 240 | { | ||
| 241 | core->cmp = cmpin; | ||
| 242 | core->init( iInitialCapacity ); | ||
| 243 | } | ||
| 244 | |||
| 245 | Heap( const MyType &rSrc ) : | ||
| 246 | SharedCore<MyType, Core>( rSrc ) | ||
| 247 | { | ||
| 248 | } | ||
| 249 | |||
| 250 | virtual ~Heap() | ||
| 251 | { | ||
| 252 | } | ||
| 253 | |||
| 254 | virtual void enqueue( const item &it ) | ||
| 255 | { | ||
| 256 | _hardCopy(); | ||
| 257 | |||
| 258 | core->enqueue( it ); | ||
| 259 | } | ||
| 260 | |||
| 261 | virtual item &peek() | ||
| 262 | { | ||
| 263 | _hardCopy(); | ||
| 264 | |||
| 265 | if( core->iFill == 0 ) | ||
| 266 | throw HeapException("Heap empty."); | ||
| 267 | return core->aItem[0]; | ||
| 268 | } | ||
| 269 | |||
| 270 | virtual const item &peek() const | ||
| 271 | { | ||
| 272 | if( core->iFill == 0 ) | ||
| 273 | throw HeapException("Heap empty."); | ||
| 274 | return core->aItem[0]; | ||
| 275 | } | ||
| 276 | |||
| 277 | virtual item dequeue() | ||
| 278 | { | ||
| 279 | _hardCopy(); | ||
| 280 | |||
| 281 | return core->dequeue(); | ||
| 282 | } | ||
| 283 | |||
| 177 | virtual bool isEmpty() const | 284 | virtual bool isEmpty() const |
| 178 | { | 285 | { |
| 179 | return (iFill==0); | 286 | return (core->iFill==0); |
| 180 | } | 287 | } |
| 181 | 288 | ||
| 182 | virtual int getSize() const | 289 | virtual int getSize() const |
| 183 | { | 290 | { |
| 184 | return iFill; | 291 | return core->iFill; |
| 185 | } | 292 | } |
| 186 | 293 | ||
| 187 | class iterator | 294 | class iterator |
| @@ -201,7 +308,7 @@ namespace Bu | |||
| 201 | { | 308 | { |
| 202 | if( pHeap == NULL ) | 309 | if( pHeap == NULL ) |
| 203 | throw Bu::ExceptionBase("Iterator not initialized."); | 310 | throw Bu::ExceptionBase("Iterator not initialized."); |
| 204 | if( iIndex < 0 || iIndex >= pHeap->iFill ) | 311 | if( iIndex < 0 || iIndex >= pHeap->core->iFill ) |
| 205 | throw Bu::ExceptionBase("Iterator out of bounds."); | 312 | throw Bu::ExceptionBase("Iterator out of bounds."); |
| 206 | } | 313 | } |
| 207 | 314 | ||
| @@ -230,12 +337,16 @@ namespace Bu | |||
| 230 | 337 | ||
| 231 | item &operator*() | 338 | item &operator*() |
| 232 | { | 339 | { |
| 233 | return pHeap->aItem[iIndex]; | 340 | pHeap->_hardCopy(); |
| 341 | |||
| 342 | return pHeap->core->aItem[iIndex]; | ||
| 234 | } | 343 | } |
| 235 | 344 | ||
| 236 | item *operator->() | 345 | item *operator->() |
| 237 | { | 346 | { |
| 238 | return &(pHeap->aItem[iIndex]); | 347 | pHeap->_hardCopy(); |
| 348 | |||
| 349 | return &(pHeap->core->aItem[iIndex]); | ||
| 239 | } | 350 | } |
| 240 | 351 | ||
| 241 | iterator &operator++() | 352 | iterator &operator++() |
| @@ -260,7 +371,7 @@ namespace Bu | |||
| 260 | { | 371 | { |
| 261 | checkValid(); | 372 | checkValid(); |
| 262 | iIndex++; | 373 | iIndex++; |
| 263 | if( iIndex >= pHeap->iFill ) | 374 | if( iIndex >= pHeap->core->iFill ) |
| 264 | iIndex = -1; | 375 | iIndex = -1; |
| 265 | 376 | ||
| 266 | return *this; | 377 | return *this; |
| @@ -279,7 +390,7 @@ namespace Bu | |||
| 279 | checkValid(); | 390 | checkValid(); |
| 280 | iterator ret( *this ); | 391 | iterator ret( *this ); |
| 281 | ret.iIndex += iDelta; | 392 | ret.iIndex += iDelta; |
| 282 | if( ret.iIndex >= pHeap->iFill ) | 393 | if( ret.iIndex >= pHeap->core->iFill ) |
| 283 | ret.iIndex = -1; | 394 | ret.iIndex = -1; |
| 284 | return ret; | 395 | return ret; |
| 285 | } | 396 | } |
| @@ -294,12 +405,12 @@ namespace Bu | |||
| 294 | return ret; | 405 | return ret; |
| 295 | } | 406 | } |
| 296 | 407 | ||
| 297 | operator bool() | 408 | operator bool() const |
| 298 | { | 409 | { |
| 299 | return iIndex != -1; | 410 | return iIndex != -1; |
| 300 | } | 411 | } |
| 301 | 412 | ||
| 302 | bool isValid() | 413 | bool isValid() const |
| 303 | { | 414 | { |
| 304 | return iIndex != -1; | 415 | return iIndex != -1; |
| 305 | } | 416 | } |
| @@ -328,7 +439,7 @@ namespace Bu | |||
| 328 | { | 439 | { |
| 329 | if( pHeap == NULL ) | 440 | if( pHeap == NULL ) |
| 330 | throw Bu::ExceptionBase("Iterator not initialized."); | 441 | throw Bu::ExceptionBase("Iterator not initialized."); |
| 331 | if( iIndex < 0 || iIndex >= pHeap->iFill ) | 442 | if( iIndex < 0 || iIndex >= pHeap->core->iFill ) |
| 332 | throw Bu::ExceptionBase("Iterator out of bounds."); | 443 | throw Bu::ExceptionBase("Iterator out of bounds."); |
| 333 | } | 444 | } |
| 334 | 445 | ||
| @@ -363,19 +474,23 @@ namespace Bu | |||
| 363 | 474 | ||
| 364 | const item &operator*() | 475 | const item &operator*() |
| 365 | { | 476 | { |
| 366 | return pHeap->aItem[iIndex]; | 477 | pHeap->_hardCopy(); |
| 478 | |||
| 479 | return pHeap->core->aItem[iIndex]; | ||
| 367 | } | 480 | } |
| 368 | 481 | ||
| 369 | const item *operator->() | 482 | const item *operator->() |
| 370 | { | 483 | { |
| 371 | return &(pHeap->aItem[iIndex]); | 484 | pHeap->_hardCopy(); |
| 485 | |||
| 486 | return &(pHeap->core->aItem[iIndex]); | ||
| 372 | } | 487 | } |
| 373 | 488 | ||
| 374 | const_iterator &operator++() | 489 | const_iterator &operator++() |
| 375 | { | 490 | { |
| 376 | checkValid(); | 491 | checkValid(); |
| 377 | iIndex++; | 492 | iIndex++; |
| 378 | if( iIndex >= pHeap->iFill ) | 493 | if( iIndex >= pHeap->core->iFill ) |
| 379 | iIndex = -1; | 494 | iIndex = -1; |
| 380 | 495 | ||
| 381 | return *this; | 496 | return *this; |
| @@ -393,7 +508,7 @@ namespace Bu | |||
| 393 | { | 508 | { |
| 394 | checkValid(); | 509 | checkValid(); |
| 395 | iIndex++; | 510 | iIndex++; |
| 396 | if( iIndex >= pHeap->iFill ) | 511 | if( iIndex >= pHeap->core->iFill ) |
| 397 | iIndex = -1; | 512 | iIndex = -1; |
| 398 | 513 | ||
| 399 | return *this; | 514 | return *this; |
| @@ -427,12 +542,12 @@ namespace Bu | |||
| 427 | return ret; | 542 | return ret; |
| 428 | } | 543 | } |
| 429 | 544 | ||
| 430 | operator bool() | 545 | operator bool() const |
| 431 | { | 546 | { |
| 432 | return iIndex != -1; | 547 | return iIndex != -1; |
| 433 | } | 548 | } |
| 434 | 549 | ||
| 435 | bool isValid() | 550 | bool isValid() const |
| 436 | { | 551 | { |
| 437 | return iIndex != -1; | 552 | return iIndex != -1; |
| 438 | } | 553 | } |
| @@ -452,14 +567,14 @@ namespace Bu | |||
| 452 | 567 | ||
| 453 | iterator begin() | 568 | iterator begin() |
| 454 | { | 569 | { |
| 455 | if( iFill == 0 ) | 570 | if( core->iFill == 0 ) |
| 456 | return end(); | 571 | return end(); |
| 457 | return iterator( this, 0 ); | 572 | return iterator( this, 0 ); |
| 458 | } | 573 | } |
| 459 | 574 | ||
| 460 | const_iterator begin() const | 575 | const_iterator begin() const |
| 461 | { | 576 | { |
| 462 | if( iFill == 0 ) | 577 | if( core->iFill == 0 ) |
| 463 | return end(); | 578 | return end(); |
| 464 | return const_iterator( this, 0 ); | 579 | return const_iterator( this, 0 ); |
| 465 | } | 580 | } |
| @@ -475,31 +590,22 @@ namespace Bu | |||
| 475 | } | 590 | } |
| 476 | 591 | ||
| 477 | 592 | ||
| 478 | private: | 593 | protected: |
| 479 | void upSize() | 594 | virtual Core *_copyCore( Core *src ) |
| 480 | { | 595 | { |
| 481 | item *aNewItems = ia.allocate( iSize*2+1 ); | 596 | Core *pRet = _allocateCore(); |
| 482 | // | 597 | |
| 483 | // We cannot use a memcopy here because we don't know what kind | 598 | pRet->iSize = src->iSize; |
| 484 | // of datastructures are being used, we have to copy them one at | 599 | pRet->iFill = src->iFill; |
| 485 | // a time. | 600 | pRet->cmp = src->cmp; |
| 486 | // | 601 | pRet->aItem = pRet->ia.allocate( pRet->iSize ); |
| 487 | for( int j = 0; j < iFill; j++ ) | 602 | for( int j = 0; j < pRet->iFill; j++ ) |
| 488 | { | 603 | { |
| 489 | ia.construct( &aNewItems[j], aItem[j] ); | 604 | pRet->ia.construct( &pRet->aItem[j], src->aItem[j] ); |
| 490 | ia.destroy( &aItem[j] ); | ||
| 491 | } | 605 | } |
| 492 | ia.deallocate( aItem, iSize ); | ||
| 493 | aItem = aNewItems; | ||
| 494 | iSize = iSize*2+1; | ||
| 495 | } | ||
| 496 | 606 | ||
| 497 | private: | 607 | return pRet; |
| 498 | int iSize; | 608 | } |
| 499 | int iFill; | ||
| 500 | item *aItem; | ||
| 501 | cmpfunc cmp; | ||
| 502 | itemalloc ia; | ||
| 503 | }; | 609 | }; |
| 504 | }; | 610 | }; |
| 505 | 611 | ||
diff --git a/src/httpget.h b/src/httpget.h index 410914c..783f880 100644 --- a/src/httpget.h +++ b/src/httpget.h | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | #include "bu/stream.h" | 11 | #include "bu/stream.h" |
| 12 | #include "bu/fstring.h" | 12 | #include "bu/fstring.h" |
| 13 | #include "bu/url.h" | 13 | #include "bu/url.h" |
| 14 | #include "bu/socket.h" | 14 | #include "bu/tcpsocket.h" |
| 15 | #include "bu/hash.h" | 15 | #include "bu/hash.h" |
| 16 | 16 | ||
| 17 | namespace Bu | 17 | namespace Bu |
| @@ -52,7 +52,7 @@ namespace Bu | |||
| 52 | private: | 52 | private: |
| 53 | Bu::Url uSrc; | 53 | Bu::Url uSrc; |
| 54 | Bu::FString sMethod; | 54 | Bu::FString sMethod; |
| 55 | Bu::Socket sSrv; | 55 | Bu::TcpSocket sSrv; |
| 56 | typedef Bu::Hash<Bu::FString,Bu::FString> MimeHash; | 56 | typedef Bu::Hash<Bu::FString,Bu::FString> MimeHash; |
| 57 | MimeHash hMimeIn; | 57 | MimeHash hMimeIn; |
| 58 | MimeHash hMimeOut; | 58 | MimeHash hMimeOut; |
diff --git a/src/itoserver.cpp b/src/itoserver.cpp index a1d804a..ea737bf 100644 --- a/src/itoserver.cpp +++ b/src/itoserver.cpp | |||
| @@ -7,9 +7,9 @@ | |||
| 7 | 7 | ||
| 8 | #include "bu/itoserver.h" | 8 | #include "bu/itoserver.h" |
| 9 | #include <errno.h> | 9 | #include <errno.h> |
| 10 | #include "bu/serversocket.h" | 10 | #include "bu/tcpserversocket.h" |
| 11 | #include "bu/client.h" | 11 | #include "bu/client.h" |
| 12 | #include "bu/socket.h" | 12 | #include "bu/tcpsocket.h" |
| 13 | 13 | ||
| 14 | #include "bu/config.h" | 14 | #include "bu/config.h" |
| 15 | 15 | ||
| @@ -41,7 +41,7 @@ Bu::ItoServer::~ItoServer() | |||
| 41 | 41 | ||
| 42 | void Bu::ItoServer::addPort( int nPort, int nPoolSize ) | 42 | void Bu::ItoServer::addPort( int nPort, int nPoolSize ) |
| 43 | { | 43 | { |
| 44 | ServerSocket *s = new ServerSocket( nPort, nPoolSize ); | 44 | TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize ); |
| 45 | int nSocket = s->getSocket(); | 45 | int nSocket = s->getSocket(); |
| 46 | FD_SET( nSocket, &fdActive ); | 46 | FD_SET( nSocket, &fdActive ); |
| 47 | hServers.insert( nSocket, s ); | 47 | hServers.insert( nSocket, s ); |
| @@ -49,7 +49,7 @@ void Bu::ItoServer::addPort( int nPort, int nPoolSize ) | |||
| 49 | 49 | ||
| 50 | void Bu::ItoServer::addPort( const FString &sAddr, int nPort, int nPoolSize ) | 50 | void Bu::ItoServer::addPort( const FString &sAddr, int nPort, int nPoolSize ) |
| 51 | { | 51 | { |
| 52 | ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); | 52 | TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize ); |
| 53 | int nSocket = s->getSocket(); | 53 | int nSocket = s->getSocket(); |
| 54 | FD_SET( nSocket, &fdActive ); | 54 | FD_SET( nSocket, &fdActive ); |
| 55 | hServers.insert( nSocket, s ); | 55 | hServers.insert( nSocket, s ); |
| @@ -92,7 +92,7 @@ void Bu::ItoServer::run() | |||
| 92 | { | 92 | { |
| 93 | if( FD_ISSET( i.getKey(), &fdRead ) ) | 93 | if( FD_ISSET( i.getKey(), &fdRead ) ) |
| 94 | { | 94 | { |
| 95 | ServerSocket *pSrv = i.getValue(); | 95 | TcpServerSocket *pSrv = i.getValue(); |
| 96 | addClient( pSrv->accept(), pSrv->getPort() ); | 96 | addClient( pSrv->accept(), pSrv->getPort() ); |
| 97 | } | 97 | } |
| 98 | } | 98 | } |
| @@ -126,7 +126,7 @@ Bu::ItoServer::ItoClient::ItoClient( ItoServer &rSrv, int iSocket, int iPort, | |||
| 126 | FD_SET( iSocket, &fdActive ); | 126 | FD_SET( iSocket, &fdActive ); |
| 127 | 127 | ||
| 128 | pClient = new Client( | 128 | pClient = new Client( |
| 129 | new Bu::Socket( iSocket ), | 129 | new Bu::TcpSocket( iSocket ), |
| 130 | new SrvClientLinkFactory( rSrv ) | 130 | new SrvClientLinkFactory( rSrv ) |
| 131 | ); | 131 | ); |
| 132 | } | 132 | } |
diff --git a/src/itoserver.h b/src/itoserver.h index c08d453..81e42cc 100644 --- a/src/itoserver.h +++ b/src/itoserver.h | |||
| @@ -26,8 +26,8 @@ | |||
| 26 | 26 | ||
| 27 | namespace Bu | 27 | namespace Bu |
| 28 | { | 28 | { |
| 29 | class ServerSocket; | 29 | class TcpServerSocket; |
| 30 | class Socket; | 30 | class TcpSocket; |
| 31 | class Client; | 31 | class Client; |
| 32 | 32 | ||
| 33 | /** | 33 | /** |
| @@ -126,7 +126,7 @@ namespace Bu | |||
| 126 | int nTimeoutSec; | 126 | int nTimeoutSec; |
| 127 | int nTimeoutUSec; | 127 | int nTimeoutUSec; |
| 128 | fd_set fdActive; | 128 | fd_set fdActive; |
| 129 | typedef Hash<int,ServerSocket *> ServerHash; | 129 | typedef Hash<int,TcpServerSocket *> ServerHash; |
| 130 | ServerHash hServers; | 130 | ServerHash hServers; |
| 131 | typedef Hash<int,ItoClient *> ClientHash; | 131 | typedef Hash<int,ItoClient *> ClientHash; |
| 132 | typedef ItoQueue<ItoClient *> ClientQueue; | 132 | typedef ItoQueue<ItoClient *> ClientQueue; |
diff --git a/src/lexer.h b/src/lexer.h index 2cb5f51..9840afe 100644 --- a/src/lexer.h +++ b/src/lexer.h | |||
| @@ -36,6 +36,10 @@ namespace Bu | |||
| 36 | } | 36 | } |
| 37 | TokenType iToken; | 37 | TokenType iToken; |
| 38 | Bu::Variant vExtra; | 38 | Bu::Variant vExtra; |
| 39 | int iStartCol; | ||
| 40 | int iStartRow; | ||
| 41 | int iEndCol; | ||
| 42 | int iEndRow; | ||
| 39 | }; | 43 | }; |
| 40 | 44 | ||
| 41 | virtual Token *nextToken()=0; | 45 | virtual Token *nextToken()=0; |
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | namespace Bu | 17 | namespace Bu |
| 18 | { | 18 | { |
| 19 | /** @cond DEVEL */ | ||
| 19 | template<typename value> | 20 | template<typename value> |
| 20 | struct ListLink | 21 | struct ListLink |
| 21 | { | 22 | { |
| @@ -24,10 +25,18 @@ namespace Bu | |||
| 24 | ListLink *pPrev; | 25 | ListLink *pPrev; |
| 25 | }; | 26 | }; |
| 26 | 27 | ||
| 27 | template<typename value, typename valuealloc, | 28 | template<typename value, typename valuealloc, typename linkalloc> |
| 28 | typename linkalloc> | 29 | class List; |
| 30 | |||
| 31 | template<typename value, typename valuealloc, typename linkalloc> | ||
| 29 | struct ListCore | 32 | struct ListCore |
| 30 | { | 33 | { |
| 34 | friend class List<value, valuealloc, linkalloc>; | ||
| 35 | friend class SharedCore< | ||
| 36 | List<value, valuealloc, linkalloc>, | ||
| 37 | ListCore<value, valuealloc, linkalloc> | ||
| 38 | >; | ||
| 39 | private: | ||
| 31 | typedef struct ListLink<value> Link; | 40 | typedef struct ListLink<value> Link; |
| 32 | ListCore() : | 41 | ListCore() : |
| 33 | pFirst( NULL ), | 42 | pFirst( NULL ), |
| @@ -177,6 +186,7 @@ namespace Bu | |||
| 177 | } | 186 | } |
| 178 | } | 187 | } |
| 179 | }; | 188 | }; |
| 189 | /** @endcond */ | ||
| 180 | 190 | ||
| 181 | /** | 191 | /** |
| 182 | * Linked list template container. This class is similar to the stl list | 192 | * Linked list template container. This class is similar to the stl list |
| @@ -189,12 +199,15 @@ namespace Bu | |||
| 189 | *@param value (typename) The type of data to store in your list | 199 | *@param value (typename) The type of data to store in your list |
| 190 | *@param valuealloc (typename) Memory Allocator for your value type | 200 | *@param valuealloc (typename) Memory Allocator for your value type |
| 191 | *@param linkalloc (typename) Memory Allocator for the list links. | 201 | *@param linkalloc (typename) Memory Allocator for the list links. |
| 202 | *@extends SharedCore | ||
| 192 | *@ingroup Containers | 203 | *@ingroup Containers |
| 193 | */ | 204 | */ |
| 194 | template<typename value, typename valuealloc=std::allocator<value>, | 205 | template<typename value, typename valuealloc=std::allocator<value>, |
| 195 | typename linkalloc=std::allocator<struct ListLink<value> > > | 206 | typename linkalloc=std::allocator<struct ListLink<value> > > |
| 196 | class List : public SharedCore< struct ListCore<value, valuealloc, | 207 | class List /** @cond */ : public SharedCore< |
| 197 | linkalloc> > | 208 | List<value, valuealloc, linkalloc>, |
| 209 | ListCore<value, valuealloc, linkalloc> | ||
| 210 | > /** @endcond */ | ||
| 198 | { | 211 | { |
| 199 | private: | 212 | private: |
| 200 | typedef struct ListLink<value> Link; | 213 | typedef struct ListLink<value> Link; |
| @@ -202,9 +215,9 @@ namespace Bu | |||
| 202 | typedef struct ListCore<value, valuealloc, linkalloc> Core; | 215 | typedef struct ListCore<value, valuealloc, linkalloc> Core; |
| 203 | 216 | ||
| 204 | protected: | 217 | protected: |
| 205 | using SharedCore< Core >::core; | 218 | using SharedCore<MyType, Core>::core; |
| 206 | using SharedCore< Core >::_hardCopy; | 219 | using SharedCore<MyType, Core>::_hardCopy; |
| 207 | using SharedCore< Core >::_allocateCore; | 220 | using SharedCore<MyType, Core>::_allocateCore; |
| 208 | 221 | ||
| 209 | public: | 222 | public: |
| 210 | struct const_iterator; | 223 | struct const_iterator; |
| @@ -215,7 +228,7 @@ namespace Bu | |||
| 215 | } | 228 | } |
| 216 | 229 | ||
| 217 | List( const MyType &src ) : | 230 | List( const MyType &src ) : |
| 218 | SharedCore< Core >( src ) | 231 | SharedCore<MyType, Core >( src ) |
| 219 | { | 232 | { |
| 220 | } | 233 | } |
| 221 | 234 | ||
diff --git a/src/listhash.cpp b/src/listhash.cpp deleted file mode 100644 index b798a1f..0000000 --- a/src/listhash.cpp +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2010 Xagasoft, All rights reserved. | ||
| 3 | * | ||
| 4 | * This file is part of the libbu++ library and is released under the | ||
| 5 | * terms of the license contained in the file LICENSE. | ||
| 6 | */ | ||
| 7 | |||
| 8 | |||
diff --git a/src/listhash.h b/src/listhash.h deleted file mode 100644 index e5ec4ee..0000000 --- a/src/listhash.h +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2010 Xagasoft, All rights reserved. | ||
| 3 | * | ||
| 4 | * This file is part of the libbu++ library and is released under the | ||
| 5 | * terms of the license contained in the file LICENSE. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef BU_LIST_HASH_H | ||
| 9 | #define BU_LIST_HASH_H | ||
| 10 | |||
| 11 | #include "bu/hash.h" | ||
| 12 | #include "bu/list.h" | ||
| 13 | |||
| 14 | namespace Bu | ||
| 15 | { | ||
| 16 | template<typename key, typename value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<Bu::List<value> >, typename challoc = std::allocator<uint32_t> > | ||
| 17 | class ListHash : public Hash<key, Bu::List<value>, sizecalc, keyalloc, valuealloc, challoc> | ||
| 18 | { | ||
| 19 | typedef Hash<key, Bu::List<value>, sizecalc, keyalloc, valuealloc, challoc> ParentType; | ||
| 20 | public: | ||
| 21 | ListHash() | ||
| 22 | { | ||
| 23 | } | ||
| 24 | |||
| 25 | ListHash( const ListHash &src ) : | ||
| 26 | ParentType( src ) | ||
| 27 | { | ||
| 28 | } | ||
| 29 | |||
| 30 | virtual ~ListHash() | ||
| 31 | { | ||
| 32 | } | ||
| 33 | |||
| 34 | ListHash &operator=( const ListHash &src ) | ||
| 35 | { | ||
| 36 | *dynamic_cast<ParentType *>(this) = | ||
| 37 | dynamic_cast<ParentType &>(src); | ||
| 38 | } | ||
| 39 | |||
| 40 | virtual void insert( const key &k, const value &v ) | ||
| 41 | { | ||
| 42 | if( !has( k ) ) | ||
| 43 | { | ||
| 44 | ParentType::insert( k, List<value>() ); | ||
| 45 | } | ||
| 46 | get( k ).append( v ); | ||
| 47 | } | ||
| 48 | |||
| 49 | private: | ||
| 50 | }; | ||
| 51 | |||
| 52 | }; | ||
| 53 | |||
| 54 | #endif | ||
diff --git a/src/myriad.h b/src/myriad.h index 3d203bb..582d310 100644 --- a/src/myriad.h +++ b/src/myriad.h | |||
| @@ -46,7 +46,7 @@ namespace Bu | |||
| 46 | * Header format is as follows: | 46 | * Header format is as follows: |
| 47 | * | 47 | * |
| 48 | * MMMMvBssssSSSS* | 48 | * MMMMvBssssSSSS* |
| 49 | * M = Magic number (FFC399BD) | 49 | * M = Magic number (0AD3FA84) |
| 50 | * v = version number | 50 | * v = version number |
| 51 | * B = Bits per int | 51 | * B = Bits per int |
| 52 | * s = Blocksize in bytes | 52 | * s = Blocksize in bytes |
diff --git a/src/myriadfs.cpp b/src/myriadfs.cpp new file mode 100644 index 0000000..af60c08 --- /dev/null +++ b/src/myriadfs.cpp | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | #include "bu/myriadfs.h" | ||
| 2 | #include "bu/myriadstream.h" | ||
| 3 | |||
| 4 | #include <string.h> | ||
| 5 | #include <unistd.h> | ||
| 6 | |||
| 7 | namespace Bu { subExceptionDef( MyriadFsException ) } | ||
| 8 | |||
| 9 | #define Myriad_Fs_MAGIC_CODE ((char *)"\xa7\x18\x8b\x39") | ||
| 10 | |||
| 11 | Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) : | ||
| 12 | rStore( rStore ), | ||
| 13 | mStore( rStore, iBlockSize ) | ||
| 14 | { | ||
| 15 | if( mStore.hasStream( 1 ) ) | ||
| 16 | { | ||
| 17 | // Check to see if this is a MyriadFs stream. | ||
| 18 | Bu::MyriadStream ms = mStore.openStream( 1 ); | ||
| 19 | char sMagic[4]; | ||
| 20 | if( ms.read( sMagic, 4 ) < 4 ) | ||
| 21 | throw MyriadFsException("The provided stream does not appear to be " | ||
| 22 | "a MyriadFs stream."); | ||
| 23 | if( ::strncmp( sMagic, Myriad_Fs_MAGIC_CODE, 4 ) ) | ||
| 24 | throw MyriadFsException("The provided stream does not appear to be " | ||
| 25 | "a MyriadFs stream."); | ||
| 26 | |||
| 27 | int8_t iVer; | ||
| 28 | } | ||
| 29 | else | ||
| 30 | { | ||
| 31 | // Create initial header stream | ||
| 32 | { | ||
| 33 | mStore.createStream( 1 ); | ||
| 34 | Bu::MyriadStream ms = mStore.openStream( 1 ); | ||
| 35 | ms.write( Myriad_Fs_MAGIC_CODE, 4 ); | ||
| 36 | int8_t iVer = 1; | ||
| 37 | int32_t iTmp = 1; | ||
| 38 | ms.write( &iVer, 1 ); | ||
| 39 | ms.write( &iBlockSize, 4 ); | ||
| 40 | ms.write( &iTmp, 4 ); // iNumNodes | ||
| 41 | iTmp = 0; | ||
| 42 | ms.write( &iTmp, 4 ); // iInode | ||
| 43 | ms.write( &iTmp, 0 ); // iPosition | ||
| 44 | } | ||
| 45 | |||
| 46 | // Create initial inode stream, with one root node. | ||
| 47 | { | ||
| 48 | mStore.createStream( 2 ); | ||
| 49 | Bu::MyriadStream ms = mStore.openStream( 2 ); | ||
| 50 | int32_t iUser = 0, iGroup = 0; | ||
| 51 | #ifndef WIN32 | ||
| 52 | iUser = getuid(); | ||
| 53 | iGroup = getgid(); | ||
| 54 | #endif | ||
| 55 | int32_t iTmp32 = 0; | ||
| 56 | int16_t iTmp16 = 0; | ||
| 57 | ms.write( &iUser, 4 ); | ||
| 58 | ms.write( &iGroup, 4 ); | ||
| 59 | ms.write( &iTmp16, 2 ); | ||
| 60 | ms.write( &iTmp16, 2 ); | ||
| 61 | iTmp32 = 3; | ||
| 62 | ms.write( &iTmp32, 4 ); | ||
| 63 | iTmp32 = 0; | ||
| 64 | ms.write( &iTmp32, 4 ); | ||
| 65 | ms.write( &iTmp16, 2 ); | ||
| 66 | } | ||
| 67 | |||
| 68 | // Create inode 0's storage stream. | ||
| 69 | { | ||
| 70 | mStore.createStream( 3 ); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | Bu::MyriadFs::~MyriadFs() | ||
| 76 | { | ||
| 77 | } | ||
| 78 | |||
diff --git a/src/myriadfs.h b/src/myriadfs.h new file mode 100644 index 0000000..42a3493 --- /dev/null +++ b/src/myriadfs.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | #ifndef MYRIAD_FS_H | ||
| 2 | #define MYRIAD_FS_H | ||
| 3 | |||
| 4 | #include "bu/myriad.h" | ||
| 5 | |||
| 6 | namespace Bu | ||
| 7 | { | ||
| 8 | class Stream; | ||
| 9 | |||
| 10 | subExceptionDecl( MyriadFsException ); | ||
| 11 | |||
| 12 | /** | ||
| 13 | * A POSIX compliant, node based filesystem built on top of Myriad. | ||
| 14 | * | ||
| 15 | * A header is placed into stream 1. | ||
| 16 | * Header format: | ||
| 17 | * int32_t iMagicHeader (A7188B39) | ||
| 18 | * int8_t iVersion (1) | ||
| 19 | * int32_t iNodeSize | ||
| 20 | * int32_t iNumNodes | ||
| 21 | * NodeLookup[iNumNodes] nNode | ||
| 22 | * | ||
| 23 | * Node lookup: | ||
| 24 | * int32_t iInode | ||
| 25 | * int32_t iPosition | ||
| 26 | * | ||
| 27 | * The node headers or inode structures have a base size of 22 bytes. | ||
| 28 | * Everything else in the block is used for the name. I.e. if you have | ||
| 29 | * a blocksize of 512 bytes then you wind up with a max name size of | ||
| 30 | * 512-22=490 characters, or a blocksize of 256 gives you 234 chraacters | ||
| 31 | * as a max. The node headers are all stored in stream 2. | ||
| 32 | * Basic node header format: | ||
| 33 | * int32_t iUser | ||
| 34 | * int32_t iGroup | ||
| 35 | * int16_t iMeta | ||
| 36 | * int16_t iPerms | ||
| 37 | * int32_t iStreamIndex | ||
| 38 | * int32_t iParentNode | ||
| 39 | * int16_t iNameSize | ||
| 40 | * char[iNameSize] sName | ||
| 41 | */ | ||
| 42 | class MyriadFs | ||
| 43 | { | ||
| 44 | public: | ||
| 45 | MyriadFs( Bu::Stream &rStore, int iBlockSize=512 ); | ||
| 46 | virtual ~MyriadFs(); | ||
| 47 | |||
| 48 | private: | ||
| 49 | Bu::Stream &rStore; | ||
| 50 | Bu::Myriad mStore; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | |||
| 54 | #endif | ||
diff --git a/src/newline.h b/src/newline.h index b69cdb5..243c876 100644 --- a/src/newline.h +++ b/src/newline.h | |||
| @@ -14,7 +14,7 @@ namespace Bu | |||
| 14 | { | 14 | { |
| 15 | /** | 15 | /** |
| 16 | * Converts new-line characters from any standard convention into linefeeds | 16 | * Converts new-line characters from any standard convention into linefeeds |
| 17 | * (\n) on reading, and converts them to either your OS's standard or a | 17 | * (\\n) on reading, and converts them to either your OS's standard or a |
| 18 | * specified standard, depending on how you construct the class. | 18 | * specified standard, depending on how you construct the class. |
| 19 | * | 19 | * |
| 20 | * If you're reading in a text file, then this filter is practically | 20 | * If you're reading in a text file, then this filter is practically |
diff --git a/src/paramproc.cpp b/src/paramproc.cpp deleted file mode 100644 index f4fd36e..0000000 --- a/src/paramproc.cpp +++ /dev/null | |||
| @@ -1,523 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2010 Xagasoft, All rights reserved. | ||
| 3 | * | ||
| 4 | * This file is part of the libbu++ library and is released under the | ||
| 5 | * terms of the license contained in the file LICENSE. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include "bu/paramproc.h" | ||
| 9 | #include <stdio.h> | ||
| 10 | #include <stdlib.h> | ||
| 11 | #include <string.h> | ||
| 12 | |||
| 13 | #define ptrtype( iitype, iiname ) \ | ||
| 14 | Bu::ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ | ||
| 15 | type( vt ##iiname ) { val.iiname = iiname; } | ||
| 16 | |||
| 17 | Bu::ParamProc::ParamPtr::ParamPtr() | ||
| 18 | { | ||
| 19 | val.str = NULL; | ||
| 20 | type = vtunset; | ||
| 21 | } | ||
| 22 | |||
| 23 | ptrtype( Bu::FString, str ); | ||
| 24 | ptrtype( uint64_t, uint64 ); | ||
| 25 | ptrtype( uint32_t, uint32 ); | ||
| 26 | ptrtype( uint16_t, uint16 ); | ||
| 27 | ptrtype( uint8_t, uint8 ); | ||
| 28 | ptrtype( int64_t, int64 ); | ||
| 29 | ptrtype( int32_t, int32 ); | ||
| 30 | ptrtype( int16_t, int16 ); | ||
| 31 | ptrtype( int8_t, int8 ); | ||
| 32 | ptrtype( float, float32 ); | ||
| 33 | ptrtype( double, float64 ); | ||
| 34 | ptrtype( long double, float96 ); | ||
| 35 | ptrtype( bool, bln ); | ||
| 36 | |||
| 37 | Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) | ||
| 38 | { | ||
| 39 | val = ptr.val; | ||
| 40 | type = ptr.type; | ||
| 41 | |||
| 42 | return *this; | ||
| 43 | } | ||
| 44 | |||
| 45 | bool Bu::ParamProc::ParamPtr::isSet() | ||
| 46 | { | ||
| 47 | return type != vtunset; | ||
| 48 | } | ||
| 49 | |||
| 50 | Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( const char *str ) | ||
| 51 | { | ||
| 52 | if( !isSet() ) return *this; | ||
| 53 | switch( type ) | ||
| 54 | { | ||
| 55 | case vtstr: | ||
| 56 | (*val.str) = str; | ||
| 57 | break; | ||
| 58 | |||
| 59 | case vtuint64: | ||
| 60 | (*val.uint64) = strtoull( str, NULL, 10 ); | ||
| 61 | break; | ||
| 62 | |||
| 63 | case vtuint32: | ||
| 64 | (*val.uint32) = strtoul( str, NULL, 10 ); | ||
| 65 | break; | ||
| 66 | |||
| 67 | case vtuint16: | ||
| 68 | (*val.uint16) = (uint16_t)strtoul( str, NULL, 10 ); | ||
| 69 | break; | ||
| 70 | |||
| 71 | case vtuint8: | ||
| 72 | (*val.uint8) = (uint8_t)strtoul( str, NULL, 10 ); | ||
| 73 | break; | ||
| 74 | |||
| 75 | case vtint64: | ||
| 76 | (*val.int64) = strtoll( str, NULL, 10 ); | ||
| 77 | break; | ||
| 78 | |||
| 79 | case vtint32: | ||
| 80 | (*val.int32) = strtol( str, NULL, 10 ); | ||
| 81 | break; | ||
| 82 | |||
| 83 | case vtint16: | ||
| 84 | (*val.int16) = (int16_t)strtol( str, NULL, 10 ); | ||
| 85 | break; | ||
| 86 | |||
| 87 | case vtint8: | ||
| 88 | (*val.int8) = (int8_t)strtol( str, NULL, 10 ); | ||
| 89 | break; | ||
| 90 | |||
| 91 | case vtfloat32: | ||
| 92 | (*val.float32) = strtof( str, NULL ); | ||
| 93 | break; | ||
| 94 | |||
| 95 | case vtfloat64: | ||
| 96 | (*val.float64) = strtod( str, NULL ); | ||
| 97 | break; | ||
| 98 | |||
| 99 | case vtfloat96: | ||
| 100 | (*val.float96) = strtold( str, NULL ); | ||
| 101 | break; | ||
| 102 | |||
| 103 | case vtbln: | ||
| 104 | if( strcasecmp("yes", str ) == 0 || | ||
| 105 | strcasecmp("true", str ) == 0 ) | ||
| 106 | { | ||
| 107 | (*val.bln) = true; | ||
| 108 | } | ||
| 109 | else | ||
| 110 | { | ||
| 111 | (*val.bln) = false; | ||
| 112 | } | ||
| 113 | break; | ||
| 114 | } | ||
| 115 | |||
| 116 | return *this; | ||
| 117 | } | ||
| 118 | |||
| 119 | Bu::ParamProc::ParamProc() | ||
| 120 | { | ||
| 121 | } | ||
| 122 | |||
| 123 | Bu::ParamProc::~ParamProc() | ||
| 124 | { | ||
| 125 | for( Bu::List<ArgSpec *>::iterator i = lArg.begin(); | ||
| 126 | i != lArg.end(); i++ ) | ||
| 127 | { | ||
| 128 | delete *i; | ||
| 129 | } | ||
| 130 | |||
| 131 | for( Bu::List<Banner *>::iterator i = lBan.begin(); | ||
| 132 | i != lBan.end(); i++ ) | ||
| 133 | { | ||
| 134 | delete *i; | ||
| 135 | } | ||
| 136 | |||
| 137 | } | ||
| 138 | /* | ||
| 139 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) | ||
| 140 | { | ||
| 141 | printf("Calling callback...\n"); | ||
| 142 | val = "Hello there, this is set in the ParamProc"; | ||
| 143 | (this->*proc)(); | ||
| 144 | }*/ | ||
| 145 | |||
| 146 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, | ||
| 147 | ParamPtr val, const char *lpDesc, const char *lpExtra, | ||
| 148 | const char *lpValue ) | ||
| 149 | { | ||
| 150 | ArgSpec *as = new ArgSpec; | ||
| 151 | if( lpWord ) | ||
| 152 | as->sWord = lpWord; | ||
| 153 | |||
| 154 | as->cChar = cChar; | ||
| 155 | as->proc = proc; | ||
| 156 | as->val = val; | ||
| 157 | if( lpDesc ) | ||
| 158 | as->sDesc = lpDesc; | ||
| 159 | if( lpExtra ) | ||
| 160 | as->sExtra = lpExtra; | ||
| 161 | if( lpValue ) | ||
| 162 | as->sValue = lpValue; | ||
| 163 | |||
| 164 | lArg.append( as ); | ||
| 165 | |||
| 166 | if( !lBan.isEmpty() ) | ||
| 167 | { | ||
| 168 | if( lBan.last()->pBefore == NULL ) | ||
| 169 | lBan.last()->pBefore = as; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, | ||
| 174 | const char *lpDesc, const char *lpExtra, | ||
| 175 | const char *lpValue ) | ||
| 176 | { | ||
| 177 | addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); | ||
| 178 | } | ||
| 179 | |||
| 180 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, | ||
| 181 | const char *lpDesc, const char *lpExtra, | ||
| 182 | const char *lpValue ) | ||
| 183 | { | ||
| 184 | addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); | ||
| 185 | } | ||
| 186 | |||
| 187 | void Bu::ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, | ||
| 188 | const char *lpDesc, const char *lpExtra, | ||
| 189 | const char *lpValue ) | ||
| 190 | { | ||
| 191 | addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); | ||
| 192 | } | ||
| 193 | |||
| 194 | void Bu::ParamProc::addParam( const char *lpWord, Proc proc, | ||
| 195 | const char *lpDesc, const char *lpExtra, | ||
| 196 | const char *lpValue ) | ||
| 197 | { | ||
| 198 | addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); | ||
| 199 | } | ||
| 200 | |||
| 201 | void Bu::ParamProc::addParam( const char *lpWord, ParamPtr val, | ||
| 202 | const char *lpDesc, const char *lpExtra, | ||
| 203 | const char *lpValue ) | ||
| 204 | { | ||
| 205 | addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); | ||
| 206 | } | ||
| 207 | |||
| 208 | void Bu::ParamProc::addParam( char cChar, Proc proc, ParamPtr val, | ||
| 209 | const char *lpDesc, const char *lpExtra, | ||
| 210 | const char *lpValue ) | ||
| 211 | { | ||
| 212 | addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); | ||
| 213 | } | ||
| 214 | |||
| 215 | void Bu::ParamProc::addParam( char cChar, Proc proc, | ||
| 216 | const char *lpDesc, const char *lpExtra, | ||
| 217 | const char *lpValue ) | ||
| 218 | { | ||
| 219 | addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); | ||
| 220 | } | ||
| 221 | |||
| 222 | void Bu::ParamProc::addParam( char cChar, ParamPtr val, | ||
| 223 | const char *lpDesc, const char *lpExtra, | ||
| 224 | const char *lpValue ) | ||
| 225 | { | ||
| 226 | addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); | ||
| 227 | } | ||
| 228 | |||
| 229 | void Bu::ParamProc::process( int argc, char *argv[] ) | ||
| 230 | { | ||
| 231 | for( int arg = 1; arg < argc; arg++ ) | ||
| 232 | { | ||
| 233 | //printf(":::%d:::%s\n", arg, argv[arg] ); | ||
| 234 | if( argv[arg][0] == '-' ) | ||
| 235 | { | ||
| 236 | if( argv[arg][1] == '-' ) | ||
| 237 | { | ||
| 238 | ArgSpec *s = checkWord( argv[arg]+2 ); | ||
| 239 | if( s ) | ||
| 240 | { | ||
| 241 | if( argv[arg][s->sWord.getSize()+2] == '=' ) | ||
| 242 | { | ||
| 243 | if( s->val.isSet() ) | ||
| 244 | { | ||
| 245 | if( s->sValue == "" ) | ||
| 246 | { | ||
| 247 | s->val = argv[arg]+s->sWord.getSize()+3; | ||
| 248 | } | ||
| 249 | else | ||
| 250 | { | ||
| 251 | s->val = s->sValue.getStr(); | ||
| 252 | } | ||
| 253 | } | ||
| 254 | if( s->proc ) | ||
| 255 | { | ||
| 256 | char **tmp = new char*[argc-arg]; | ||
| 257 | tmp[0] = argv[arg]+s->sWord.getSize()+3; | ||
| 258 | for( int k = 1; k < argc-arg; k++ ) | ||
| 259 | tmp[k] = argv[arg+k]; | ||
| 260 | int ret = (this->*s->proc)( argc-arg, tmp ); | ||
| 261 | if( ret > 0 ) | ||
| 262 | { | ||
| 263 | arg += ret-1; | ||
| 264 | } | ||
| 265 | delete tmp; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | else | ||
| 269 | { | ||
| 270 | int add = 0; | ||
| 271 | if( s->val.isSet() ) | ||
| 272 | { | ||
| 273 | if( s->sValue == "" ) | ||
| 274 | { | ||
| 275 | if( arg+1 >= argc ) | ||
| 276 | { | ||
| 277 | return; | ||
| 278 | } | ||
| 279 | s->val = argv[arg+1]; | ||
| 280 | add++; | ||
| 281 | } | ||
| 282 | else | ||
| 283 | { | ||
| 284 | s->val = s->sValue.getStr(); | ||
| 285 | } | ||
| 286 | } | ||
| 287 | if( s->proc ) | ||
| 288 | { | ||
| 289 | int ret = (this->*s->proc)( | ||
| 290 | argc-arg-1, argv+arg+1 ); | ||
| 291 | |||
| 292 | if( ret > add ) | ||
| 293 | add = 0; | ||
| 294 | else | ||
| 295 | add -= ret; | ||
| 296 | arg += ret; | ||
| 297 | } | ||
| 298 | arg += add; | ||
| 299 | } | ||
| 300 | continue; | ||
| 301 | } | ||
| 302 | else | ||
| 303 | { | ||
| 304 | unknownParam( argc-arg, argv+arg ); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | else | ||
| 308 | { | ||
| 309 | for( int chr = 1; argv[arg][chr]; chr++ ) | ||
| 310 | { | ||
| 311 | ArgSpec *s = checkLetr( argv[arg][chr] ); | ||
| 312 | if( s ) | ||
| 313 | { | ||
| 314 | if( argv[arg][chr+1] != '\0' ) | ||
| 315 | { | ||
| 316 | bool bUsed = false; | ||
| 317 | if( s->val.isSet() ) | ||
| 318 | { | ||
| 319 | if( s->sValue == "" ) | ||
| 320 | { | ||
| 321 | s->val = argv[arg]+chr+1; | ||
| 322 | bUsed = true; | ||
| 323 | } | ||
| 324 | else | ||
| 325 | { | ||
| 326 | s->val = s->sValue.getStr(); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | if( s->proc ) | ||
| 330 | { | ||
| 331 | char **tmp = new char*[argc-arg]; | ||
| 332 | tmp[0] = argv[arg]+chr+1; | ||
| 333 | for( int k = 1; k < argc-arg; k++ ) | ||
| 334 | tmp[k] = argv[arg+k]; | ||
| 335 | int ret = (this->*s->proc)( argc-arg, tmp ); | ||
| 336 | if( ret > 0 ) | ||
| 337 | { | ||
| 338 | arg += ret - 1; | ||
| 339 | delete tmp; | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | delete tmp; | ||
| 343 | } | ||
| 344 | if( bUsed ) | ||
| 345 | { | ||
| 346 | break; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | else | ||
| 350 | { | ||
| 351 | bool bUsed = false; | ||
| 352 | if( s->val.isSet() ) | ||
| 353 | { | ||
| 354 | if( s->sValue == "" ) | ||
| 355 | { | ||
| 356 | s->val = argv[arg+1]; | ||
| 357 | bUsed = true; | ||
| 358 | } | ||
| 359 | else | ||
| 360 | { | ||
| 361 | s->val = s->sValue.getStr(); | ||
| 362 | } | ||
| 363 | } | ||
| 364 | if( s->proc ) | ||
| 365 | { | ||
| 366 | int ret = (this->*s->proc)( | ||
| 367 | argc-arg-1, argv+arg+1 | ||
| 368 | ); | ||
| 369 | if( ret > 0 ) | ||
| 370 | { | ||
| 371 | arg += ret; | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | } | ||
| 375 | if( bUsed ) | ||
| 376 | { | ||
| 377 | arg++; | ||
| 378 | break; | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | else | ||
| 383 | { | ||
| 384 | unknownParam( argc-arg, argv+arg ); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | } | ||
| 388 | } | ||
| 389 | else | ||
| 390 | { | ||
| 391 | cmdParam( argc-arg, argv+arg ); | ||
| 392 | } | ||
| 393 | } | ||
| 394 | } | ||
| 395 | |||
| 396 | Bu::ParamProc::ArgSpec *Bu::ParamProc::checkWord( const char *arg ) | ||
| 397 | { | ||
| 398 | //printf("Checking \"%s\"...\n", arg ); | ||
| 399 | Bu::List<ArgSpec *>::const_iterator i = lArg.begin(); | ||
| 400 | for( ; i != lArg.end(); i++ ) | ||
| 401 | { | ||
| 402 | if( (*i)->sWord == "" ) | ||
| 403 | continue; | ||
| 404 | |||
| 405 | if( !strcmp( (*i)->sWord.getStr(), arg ) ) | ||
| 406 | return *i; | ||
| 407 | |||
| 408 | if( (*i)->val.isSet() ) | ||
| 409 | { | ||
| 410 | if( !strncmp( (*i)->sWord.getStr(), arg, (*i)->sWord.getSize() ) && | ||
| 411 | arg[(*i)->sWord.getSize()] == '=' ) | ||
| 412 | { | ||
| 413 | return *i; | ||
| 414 | } | ||
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 418 | return NULL; | ||
| 419 | } | ||
| 420 | |||
| 421 | Bu::ParamProc::ArgSpec *Bu::ParamProc::checkLetr( const char arg ) | ||
| 422 | { | ||
| 423 | //printf("Checking \'%c\'...\n", arg ); | ||
| 424 | Bu::List<ArgSpec *>::const_iterator i = lArg.begin(); | ||
| 425 | for( ; i != lArg.end(); i++ ) | ||
| 426 | { | ||
| 427 | if( (*i)->cChar == '\0' ) | ||
| 428 | continue; | ||
| 429 | |||
| 430 | if( (*i)->cChar == arg ) | ||
| 431 | { | ||
| 432 | return *i; | ||
| 433 | } | ||
| 434 | } | ||
| 435 | |||
| 436 | return NULL; | ||
| 437 | } | ||
| 438 | |||
| 439 | int Bu::ParamProc::cmdParam( int /*argc*/, char *argv[] ) | ||
| 440 | { | ||
| 441 | printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); | ||
| 442 | return 0; | ||
| 443 | } | ||
| 444 | |||
| 445 | int Bu::ParamProc::unknownParam( int /*argc*/, char *argv[] ) | ||
| 446 | { | ||
| 447 | printf("Unknown parameter \"%s\" found!\n", argv[0] ); | ||
| 448 | return 0; | ||
| 449 | } | ||
| 450 | |||
| 451 | int Bu::ParamProc::help( int /*argc*/, char * /*argv*/ [] ) | ||
| 452 | { | ||
| 453 | Bu::List<Banner *>::const_iterator b = lBan.begin(); | ||
| 454 | Bu::List<ArgSpec *>::const_iterator i = lArg.begin(); | ||
| 455 | int len=0; | ||
| 456 | for( ; i != lArg.end(); i++ ) | ||
| 457 | { | ||
| 458 | if( len < (*i)->sWord.getSize() + (*i)->sExtra.getSize() ) | ||
| 459 | len = (*i)->sWord.getSize() + (*i)->sExtra.getSize(); | ||
| 460 | } | ||
| 461 | char fmt[10]; | ||
| 462 | sprintf( fmt, "%%-%ds ", len ); | ||
| 463 | |||
| 464 | for( i = lArg.begin(); i != lArg.end(); i++ ) | ||
| 465 | { | ||
| 466 | if( b != lBan.end() ) | ||
| 467 | { | ||
| 468 | if( (*b)->pBefore == (*i) ) | ||
| 469 | { | ||
| 470 | printf( (*b)->sBanner.getStr() ); | ||
| 471 | b++; | ||
| 472 | } | ||
| 473 | } | ||
| 474 | printf(" "); | ||
| 475 | if( (*i)->cChar ) | ||
| 476 | { | ||
| 477 | if( (*i)->sWord.getStr() ) | ||
| 478 | { | ||
| 479 | printf("-%c, ", (*i)->cChar ); | ||
| 480 | } | ||
| 481 | else | ||
| 482 | { | ||
| 483 | printf("-%c ", (*i)->cChar ); | ||
| 484 | } | ||
| 485 | } | ||
| 486 | else | ||
| 487 | { | ||
| 488 | printf(" "); | ||
| 489 | } | ||
| 490 | if( (*i)->sWord.getStr() ) | ||
| 491 | { | ||
| 492 | printf("--"); | ||
| 493 | Bu::FString sTmp = (*i)->sWord.getStr(); | ||
| 494 | if( (*i)->sExtra.getStr() ) | ||
| 495 | sTmp += (*i)->sExtra.getStr(); | ||
| 496 | printf( fmt, sTmp.getStr() ); | ||
| 497 | } | ||
| 498 | else | ||
| 499 | { | ||
| 500 | printf(" "); | ||
| 501 | printf(fmt, "" ); | ||
| 502 | } | ||
| 503 | printf("%s\n", (*i)->sDesc.getStr() ); | ||
| 504 | } | ||
| 505 | if( b != lBan.end() ) | ||
| 506 | { | ||
| 507 | if( (*b)->pBefore == NULL ) | ||
| 508 | { | ||
| 509 | printf( (*b)->sBanner.getStr() ); | ||
| 510 | } | ||
| 511 | } | ||
| 512 | |||
| 513 | exit( 0 ); | ||
| 514 | } | ||
| 515 | |||
| 516 | void Bu::ParamProc::addHelpBanner( const char *sHelpBanner ) | ||
| 517 | { | ||
| 518 | Banner *pBan = new Banner; | ||
| 519 | pBan->sBanner = sHelpBanner; | ||
| 520 | pBan->pBefore = NULL; | ||
| 521 | lBan.append( pBan ); | ||
| 522 | } | ||
| 523 | |||
diff --git a/src/paramproc.h b/src/paramproc.h deleted file mode 100644 index ddc1876..0000000 --- a/src/paramproc.h +++ /dev/null | |||
| @@ -1,163 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2010 Xagasoft, All rights reserved. | ||
| 3 | * | ||
| 4 | * This file is part of the libbu++ library and is released under the | ||
| 5 | * terms of the license contained in the file LICENSE. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef BU_PARAM_PROC_H | ||
| 9 | #define BU_PARAM_PROC_H | ||
| 10 | |||
| 11 | #include <stdint.h> | ||
| 12 | #include "bu/list.h" | ||
| 13 | #include "bu/fstring.h" | ||
| 14 | |||
| 15 | namespace Bu | ||
| 16 | { | ||
| 17 | class ParamProc | ||
| 18 | { | ||
| 19 | public: | ||
| 20 | class ParamPtr | ||
| 21 | { | ||
| 22 | public: | ||
| 23 | ParamPtr(); | ||
| 24 | ParamPtr( Bu::FString *str ); | ||
| 25 | ParamPtr( uint64_t *uint64 ); | ||
| 26 | ParamPtr( uint32_t *uint32 ); | ||
| 27 | ParamPtr( uint16_t *uint16 ); | ||
| 28 | ParamPtr( uint8_t *uint8 ); | ||
| 29 | ParamPtr( int64_t *int64 ); | ||
| 30 | ParamPtr( int32_t *int32 ); | ||
| 31 | ParamPtr( int16_t *int16 ); | ||
| 32 | ParamPtr( int8_t *int8 ); | ||
| 33 | ParamPtr( float *float32 ); | ||
| 34 | ParamPtr( double *float64 ); | ||
| 35 | ParamPtr( long double *float96 ); | ||
| 36 | ParamPtr( bool *bln ); | ||
| 37 | |||
| 38 | enum | ||
| 39 | { | ||
| 40 | vtunset, | ||
| 41 | vtstr, | ||
| 42 | vtuint64, | ||
| 43 | vtuint32, | ||
| 44 | vtuint16, | ||
| 45 | vtuint8, | ||
| 46 | vtint64, | ||
| 47 | vtint32, | ||
| 48 | vtint16, | ||
| 49 | vtint8, | ||
| 50 | vtfloat32, | ||
| 51 | vtfloat64, | ||
| 52 | vtfloat96, | ||
| 53 | vtbln, | ||
| 54 | }; | ||
| 55 | ParamPtr &operator=( ParamPtr &ptr ); | ||
| 56 | ParamPtr &operator=( const char *str ); | ||
| 57 | |||
| 58 | bool isSet(); | ||
| 59 | |||
| 60 | private: | ||
| 61 | int type; | ||
| 62 | union | ||
| 63 | { | ||
| 64 | Bu::FString *str; | ||
| 65 | uint64_t *uint64; | ||
| 66 | uint32_t *uint32; | ||
| 67 | uint16_t *uint16; | ||
| 68 | uint8_t *uint8; | ||
| 69 | int64_t *int64; | ||
| 70 | int32_t *int32; | ||
| 71 | int16_t *int16; | ||
| 72 | int8_t *int8; | ||
| 73 | float *float32; | ||
| 74 | double *float64; | ||
| 75 | long double *float96; | ||
| 76 | bool *bln; | ||
| 77 | } val; | ||
| 78 | }; | ||
| 79 | |||
| 80 | typedef int (ParamProc::*Proc)( int, char *[] ); | ||
| 81 | |||
| 82 | typedef struct ArgSpec | ||
| 83 | { | ||
| 84 | uint8_t nFlags; | ||
| 85 | Bu::FString sWord; | ||
| 86 | char cChar; | ||
| 87 | Proc proc; | ||
| 88 | ParamProc::ParamPtr val; | ||
| 89 | Bu::FString sExtra; | ||
| 90 | Bu::FString sDesc; | ||
| 91 | Bu::FString sValue; | ||
| 92 | } ArgSpec; | ||
| 93 | |||
| 94 | public: | ||
| 95 | DEPRECATED | ||
| 96 | ParamProc(); | ||
| 97 | virtual ~ParamProc(); | ||
| 98 | |||
| 99 | void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, | ||
| 100 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
| 101 | const char *lpValue=NULL | ||
| 102 | ); | ||
| 103 | void addParam( const char *lpWord, char cChar, Proc proc, | ||
| 104 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
| 105 | const char *lpValue=NULL | ||
| 106 | ); | ||
| 107 | void addParam( const char *lpWord, char cChar, ParamPtr val, | ||
| 108 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
| 109 | const char *lpValue=NULL | ||
| 110 | ); | ||
| 111 | |||
| 112 | void addParam( const char *lpWord, Proc proc, ParamPtr val, | ||
| 113 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
| 114 | const char *lpValue=NULL | ||
| 115 | ); | ||
| 116 | void addParam( const char *lpWord, Proc proc, | ||
| 117 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
| 118 | const char *lpValue=NULL | ||
| 119 | ); | ||
| 120 | void addParam( const char *lpWord, ParamPtr val, | ||
| 121 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
| 122 | const char *lpValue=NULL | ||
| 123 | ); | ||
| 124 | |||
| 125 | void addParam( char cChar, Proc proc, ParamPtr val, | ||
| 126 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
| 127 | const char *lpValue=NULL | ||
| 128 | ); | ||
| 129 | void addParam( char cChar, Proc proc, | ||
| 130 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
| 131 | const char *lpValue=NULL | ||
| 132 | ); | ||
| 133 | void addParam( char cChar, ParamPtr val, | ||
| 134 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
| 135 | const char *lpValue=NULL | ||
| 136 | ); | ||
| 137 | |||
| 138 | void process( int argc, char *argv[] ); | ||
| 139 | void addHelpBanner( const char *sHelpBanner ); | ||
| 140 | |||
| 141 | private: | ||
| 142 | ArgSpec *checkWord( const char *arg ); | ||
| 143 | ArgSpec *checkLetr( const char arg ); | ||
| 144 | |||
| 145 | public: | ||
| 146 | virtual int cmdParam( int argc, char *argv[] ); | ||
| 147 | virtual int unknownParam( int argc, char *argv[] ); | ||
| 148 | virtual int help( int argc, char *argv[] ); | ||
| 149 | |||
| 150 | private: | ||
| 151 | typedef struct Banner | ||
| 152 | { | ||
| 153 | Bu::FString sBanner; | ||
| 154 | ArgSpec *pBefore; | ||
| 155 | } Banner; | ||
| 156 | Bu::List<Banner *> lBan; | ||
| 157 | Bu::List<ArgSpec *> lArg; | ||
| 158 | }; | ||
| 159 | } | ||
| 160 | |||
| 161 | #define mkproc( cls ) static_cast<int (Bu::ParamProc::*)( int, char *[])>(&cls) | ||
| 162 | |||
| 163 | #endif | ||
diff --git a/src/parser.cpp b/src/parser.cpp index e4e8ae5..4ad4ff9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp | |||
| @@ -22,16 +22,25 @@ void Bu::Parser::popLexer() | |||
| 22 | delete sLexer.peekPop(); | 22 | delete sLexer.peekPop(); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | Lexer::Token *Bu::Parser::popToken() | ||
| 26 | { | ||
| 27 | return sToken.peekPop(); | ||
| 28 | } | ||
| 29 | |||
| 30 | void Bu::Parser::pushToken( Lexer::Token *pTok ) | ||
| 31 | { | ||
| 32 | sToken.push( pTok ); | ||
| 33 | } | ||
| 34 | |||
| 25 | void Bu::Parser::parse() | 35 | void Bu::Parser::parse() |
| 26 | { | 36 | { |
| 27 | int iCurNt = iRootNonTerminal; | 37 | int iCurNt = iRootNonTerminal; |
| 28 | Lexer::Token *ptCur = sLexer.peek()->nextToken(); | 38 | Lexer::Token *ptCur = sLexer.peek()->nextToken(); |
| 29 | sio << "Token: " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; | 39 | sio << "Token(a): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; |
| 30 | selectProduction( iCurNt, ptCur ); | 40 | selectProduction( iCurNt, ptCur ); |
| 31 | 41 | ||
| 32 | while( !sState.isEmpty() ) | 42 | while( !sState.isEmpty() ) |
| 33 | { | 43 | { |
| 34 | sio << "Currently: " << *sState.peek() << sio.nl; | ||
| 35 | switch( (*sState.peek()).eType ) | 44 | switch( (*sState.peek()).eType ) |
| 36 | { | 45 | { |
| 37 | case State::typeTerminal: | 46 | case State::typeTerminal: |
| @@ -42,7 +51,7 @@ void Bu::Parser::parse() | |||
| 42 | advanceState(); | 51 | advanceState(); |
| 43 | delete ptCur; | 52 | delete ptCur; |
| 44 | ptCur = sLexer.peek()->nextToken(); | 53 | ptCur = sLexer.peek()->nextToken(); |
| 45 | sio << "Token: " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; | 54 | sio << "Token(b): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; |
| 46 | } | 55 | } |
| 47 | else | 56 | else |
| 48 | { | 57 | { |
| @@ -59,7 +68,7 @@ void Bu::Parser::parse() | |||
| 59 | sToken.push( ptCur ); | 68 | sToken.push( ptCur ); |
| 60 | 69 | ||
| 61 | ptCur = sLexer.peek()->nextToken(); | 70 | ptCur = sLexer.peek()->nextToken(); |
| 62 | sio << "Token: " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; | 71 | sio << "Token(c): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; |
| 63 | } | 72 | } |
| 64 | else | 73 | else |
| 65 | { | 74 | { |
| @@ -72,7 +81,7 @@ void Bu::Parser::parse() | |||
| 72 | << (*sState.peek()).iIndex << sio.nl; | 81 | << (*sState.peek()).iIndex << sio.nl; |
| 73 | { | 82 | { |
| 74 | int iNt = (*sState.peek()).iIndex; | 83 | int iNt = (*sState.peek()).iIndex; |
| 75 | advanceState(); | 84 | sio << "Current state: " << *sState.peek() << sio.nl; |
| 76 | if( !selectProduction( iNt, ptCur ) ) | 85 | if( !selectProduction( iNt, ptCur ) ) |
| 77 | { | 86 | { |
| 78 | throw Bu::ExceptionBase("Error parsing code."); | 87 | throw Bu::ExceptionBase("Error parsing code."); |
| @@ -132,7 +141,11 @@ bool Bu::Parser::selectProduction( int iNt, Lexer::Token *ptCur ) | |||
| 132 | } | 141 | } |
| 133 | } | 142 | } |
| 134 | if( nt.bCanSkip ) | 143 | if( nt.bCanSkip ) |
| 144 | { | ||
| 145 | sio << "Nothing matches, skipping non-terminal." << sio.nl; | ||
| 146 | advanceState(); | ||
| 135 | return true; | 147 | return true; |
| 148 | } | ||
| 136 | sio << "-->(Found nothing)" << sio.nl; | 149 | sio << "-->(Found nothing)" << sio.nl; |
| 137 | return false; | 150 | return false; |
| 138 | } | 151 | } |
| @@ -148,6 +161,7 @@ void Bu::Parser::advanceState() | |||
| 148 | sio.decIndent(); | 161 | sio.decIndent(); |
| 149 | sState.pop(); | 162 | sState.pop(); |
| 150 | sio << "State advanced, End of production." << sio.nl; | 163 | sio << "State advanced, End of production." << sio.nl; |
| 164 | advanceState(); | ||
| 151 | return; | 165 | return; |
| 152 | } | 166 | } |
| 153 | sio << "State advanced, now: " << *(sState.peek()) << sio.nl; | 167 | sio << "State advanced, now: " << *(sState.peek()) << sio.nl; |
| @@ -191,6 +205,11 @@ int Bu::Parser::getNonTerminalId( const Bu::FString &sName ) | |||
| 191 | return hNonTerminalName.get( sName ); | 205 | return hNonTerminalName.get( sName ); |
| 192 | } | 206 | } |
| 193 | 207 | ||
| 208 | bool Bu::Parser::hasNonTerminal( const Bu::FString &sName ) | ||
| 209 | { | ||
| 210 | return hNonTerminalName.has( sName ); | ||
| 211 | } | ||
| 212 | |||
| 194 | int Bu::Parser::addReduction( const Bu::FString &sName, const Reduction &r ) | 213 | int Bu::Parser::addReduction( const Bu::FString &sName, const Reduction &r ) |
| 195 | { | 214 | { |
| 196 | int iId = aReduction.getSize(); | 215 | int iId = aReduction.getSize(); |
| @@ -217,6 +236,11 @@ int Bu::Parser::getReductionId( const Bu::FString &sName ) | |||
| 217 | return hReductionName.get( sName ); | 236 | return hReductionName.get( sName ); |
| 218 | } | 237 | } |
| 219 | 238 | ||
| 239 | bool Bu::Parser::hasReduction( const Bu::FString &sName ) | ||
| 240 | { | ||
| 241 | return hReductionName.has( sName ); | ||
| 242 | } | ||
| 243 | |||
| 220 | // | 244 | // |
| 221 | // Bu::Parser::State | 245 | // Bu::Parser::State |
| 222 | // | 246 | // |
diff --git a/src/parser.h b/src/parser.h index 5b5d4a8..a925188 100644 --- a/src/parser.h +++ b/src/parser.h | |||
| @@ -34,6 +34,9 @@ namespace Bu | |||
| 34 | */ | 34 | */ |
| 35 | void popLexer(); | 35 | void popLexer(); |
| 36 | 36 | ||
| 37 | Lexer::Token *popToken(); | ||
| 38 | void pushToken( Lexer::Token *pTok ); | ||
| 39 | |||
| 37 | /** | 40 | /** |
| 38 | * Execute a parse. | 41 | * Execute a parse. |
| 39 | */ | 42 | */ |
| @@ -88,11 +91,13 @@ namespace Bu | |||
| 88 | int addNonTerminal( const Bu::FString &sName ); | 91 | int addNonTerminal( const Bu::FString &sName ); |
| 89 | void setNonTerminal( const Bu::FString &sName, NonTerminal &nt ); | 92 | void setNonTerminal( const Bu::FString &sName, NonTerminal &nt ); |
| 90 | int getNonTerminalId( const Bu::FString &sName ); | 93 | int getNonTerminalId( const Bu::FString &sName ); |
| 94 | bool hasNonTerminal( const Bu::FString &sName ); | ||
| 91 | 95 | ||
| 92 | int addReduction( const Bu::FString &sName, const Reduction &r ); | 96 | int addReduction( const Bu::FString &sName, const Reduction &r ); |
| 93 | int addReduction( const Bu::FString &sName ); | 97 | int addReduction( const Bu::FString &sName ); |
| 94 | void setReduction( const Bu::FString &sName, const Reduction &r ); | 98 | void setReduction( const Bu::FString &sName, const Reduction &r ); |
| 95 | int getReductionId( const Bu::FString &sName ); | 99 | int getReductionId( const Bu::FString &sName ); |
| 100 | bool hasReduction( const Bu::FString &sName ); | ||
| 96 | 101 | ||
| 97 | private: | 102 | private: |
| 98 | bool selectProduction( int iNt, Lexer::Token *ptCur ); | 103 | bool selectProduction( int iNt, Lexer::Token *ptCur ); |
diff --git a/src/ringbuffer.h b/src/ringbuffer.h index e984d18..f4fd58c 100644 --- a/src/ringbuffer.h +++ b/src/ringbuffer.h | |||
| @@ -10,97 +10,218 @@ | |||
| 10 | 10 | ||
| 11 | #include <memory> | 11 | #include <memory> |
| 12 | #include "bu/exceptionbase.h" | 12 | #include "bu/exceptionbase.h" |
| 13 | #include "bu/queue.h" | ||
| 14 | #include "bu/sharedcore.h" | ||
| 13 | 15 | ||
| 14 | namespace Bu | 16 | namespace Bu |
| 15 | { | 17 | { |
| 16 | /** | 18 | template<typename value, typename valuealloc> class RingBuffer; |
| 17 | *@ingroup Containers | 19 | |
| 18 | */ | 20 | /** @cond DEVEL */ |
| 19 | template<typename value, typename valuealloc=std::allocator<value> > | 21 | template<typename value, typename valuealloc> |
| 20 | class RingBuffer | 22 | class RingBufferCore |
| 21 | { | 23 | { |
| 22 | public: | 24 | friend class RingBuffer<value, valuealloc>; |
| 23 | RingBuffer( int nCapacity ) : | 25 | friend class SharedCore<RingBuffer<value, valuealloc>, |
| 24 | nCapacity( nCapacity ), | 26 | RingBufferCore<value, valuealloc> >; |
| 25 | nStart( -1 ), | 27 | private: |
| 26 | nEnd( -2 ) | 28 | RingBufferCore() : |
| 29 | iCapacity( 0 ), | ||
| 30 | iStart( -1 ), | ||
| 31 | iEnd( -2 ), | ||
| 32 | aData( NULL ) | ||
| 27 | { | 33 | { |
| 28 | aData = va.allocate( nCapacity ); | ||
| 29 | } | 34 | } |
| 30 | 35 | ||
| 31 | virtual ~RingBuffer() | 36 | virtual ~RingBufferCore() |
| 32 | { | 37 | { |
| 33 | for( int j = nStart; j < nEnd; j=(j+1%nCapacity) ) | 38 | clear(); |
| 34 | { | ||
| 35 | va.destroy( &aData[j] ); | ||
| 36 | } | ||
| 37 | va.deallocate( aData, nCapacity ); | ||
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | int getCapacity() | 41 | void init( int iNewCapacity ) |
| 41 | { | 42 | { |
| 42 | return nCapacity; | 43 | if( iCapacity > 0 ) |
| 43 | } | 44 | return; |
| 44 | 45 | ||
| 45 | bool isFilled() | 46 | iCapacity = iNewCapacity; |
| 46 | { | 47 | iStart = -1; |
| 47 | return (nStart == nEnd); | 48 | iEnd = -2; |
| 49 | aData = va.allocate( iCapacity ); | ||
| 48 | } | 50 | } |
| 49 | 51 | ||
| 50 | bool isEmpty() | 52 | void clear() |
| 51 | { | 53 | { |
| 52 | return (nStart == -1); | 54 | for( int j = iStart; j < iEnd; j=(j+1%iCapacity) ) |
| 55 | { | ||
| 56 | va.destroy( &aData[j] ); | ||
| 57 | } | ||
| 58 | va.deallocate( aData, iCapacity ); | ||
| 59 | aData = NULL; | ||
| 60 | iCapacity = 0; | ||
| 53 | } | 61 | } |
| 54 | 62 | ||
| 55 | void enqueue( const value &v ) | 63 | void enqueue( const value &v ) |
| 56 | { | 64 | { |
| 57 | if( nStart == -1 ) | 65 | if( iStart == -1 ) |
| 58 | { | 66 | { |
| 59 | nStart = 0; | 67 | iStart = 0; |
| 60 | nEnd = 1; | 68 | iEnd = 1; |
| 61 | va.construct( &aData[0], v ); | 69 | va.construct( &aData[0], v ); |
| 62 | } | 70 | } |
| 63 | else if( nStart == nEnd ) | 71 | else if( iStart == iEnd ) |
| 64 | { | 72 | { |
| 65 | throw ExceptionBase("Hey, it's full!"); | 73 | throw ExceptionBase("Hey, it's full!"); |
| 66 | } | 74 | } |
| 67 | else | 75 | else |
| 68 | { | 76 | { |
| 69 | va.construct( &aData[nEnd], v ); | 77 | va.construct( &aData[iEnd], v ); |
| 70 | nEnd = (nEnd+1)%nCapacity; | 78 | iEnd = (iEnd+1)%iCapacity; |
| 71 | } | 79 | } |
| 72 | } | 80 | } |
| 73 | 81 | ||
| 74 | value dequeue() | 82 | value dequeue() |
| 75 | { | 83 | { |
| 76 | if( nStart == -1 ) | 84 | if( iStart == -1 ) |
| 77 | { | 85 | { |
| 78 | throw ExceptionBase("No data"); | 86 | throw ExceptionBase("No data"); |
| 79 | } | 87 | } |
| 80 | else | 88 | else |
| 81 | { | 89 | { |
| 82 | value &v = aData[nStart]; | 90 | value &v = aData[iStart]; |
| 83 | va.destroy( &aData[nStart] ); | 91 | va.destroy( &aData[iStart] ); |
| 84 | nStart = (nStart+1)%nCapacity; | 92 | iStart = (iStart+1)%iCapacity; |
| 85 | if( nStart == nEnd ) | 93 | if( iStart == iEnd ) |
| 86 | { | 94 | { |
| 87 | nStart = -1; | 95 | iStart = -1; |
| 88 | nEnd = -2; | 96 | iEnd = -2; |
| 89 | } | 97 | } |
| 90 | return v; | 98 | return v; |
| 91 | } | 99 | } |
| 92 | } | 100 | } |
| 93 | 101 | ||
| 94 | value &operator[]( int nIndex ) | 102 | value &get( int iIndex ) |
| 95 | { | 103 | { |
| 96 | return aData[(nIndex+nStart)%nCapacity]; | 104 | return aData[(iIndex+iStart)%iCapacity]; |
| 97 | } | 105 | } |
| 98 | 106 | ||
| 99 | private: | 107 | int getSize() |
| 100 | int nCapacity; | 108 | { |
| 109 | if( iStart < 0 ) | ||
| 110 | return 0; | ||
| 111 | if( iEnd == iStart ) | ||
| 112 | return iCapacity; | ||
| 113 | if( iEnd < iStart ) | ||
| 114 | return iEnd-iStart; | ||
| 115 | return iCapacity-(iEnd-iStart); | ||
| 116 | } | ||
| 117 | |||
| 118 | int iCapacity; | ||
| 119 | int iStart, iEnd; | ||
| 101 | value *aData; | 120 | value *aData; |
| 102 | valuealloc va; | 121 | valuealloc va; |
| 103 | int nStart, nEnd; | 122 | }; |
| 123 | /** @endcond */ | ||
| 124 | |||
| 125 | /** | ||
| 126 | *@ingroup Containers | ||
| 127 | */ | ||
| 128 | template<typename value, typename valuealloc=std::allocator<value> > | ||
| 129 | class RingBuffer : public Queue<value>, public SharedCore< | ||
| 130 | RingBuffer<value, valuealloc>, | ||
| 131 | RingBufferCore<value, valuealloc> | ||
| 132 | > | ||
| 133 | { | ||
| 134 | private: | ||
| 135 | typedef RingBuffer<value, valuealloc> MyType; | ||
| 136 | typedef RingBufferCore<value, valuealloc> Core; | ||
| 137 | |||
| 138 | protected: | ||
| 139 | using SharedCore<MyType, Core>::core; | ||
| 140 | using SharedCore<MyType, Core>::_hardCopy; | ||
| 141 | using SharedCore<MyType, Core>::_allocateCore; | ||
| 142 | |||
| 143 | public: | ||
| 144 | RingBuffer( int iCapacity ) | ||
| 145 | { | ||
| 146 | core->init( iCapacity ); | ||
| 147 | } | ||
| 148 | |||
| 149 | RingBuffer( const RingBuffer &rSrc ) : | ||
| 150 | SharedCore<MyType, Core>( rSrc ) | ||
| 151 | { | ||
| 152 | } | ||
| 153 | |||
| 154 | virtual ~RingBuffer() | ||
| 155 | { | ||
| 156 | } | ||
| 157 | |||
| 158 | int getCapacity() const | ||
| 159 | { | ||
| 160 | return core->iCapacity; | ||
| 161 | } | ||
| 162 | |||
| 163 | bool isFilled() const | ||
| 164 | { | ||
| 165 | return (core->iStart == core->iEnd); | ||
| 166 | } | ||
| 167 | |||
| 168 | bool isEmpty() const | ||
| 169 | { | ||
| 170 | return (core->iStart == -1); | ||
| 171 | } | ||
| 172 | |||
| 173 | virtual void enqueue( const value &v ) | ||
| 174 | { | ||
| 175 | _hardCopy(); | ||
| 176 | |||
| 177 | core->enqueue( v ); | ||
| 178 | } | ||
| 179 | |||
| 180 | virtual value dequeue() | ||
| 181 | { | ||
| 182 | _hardCopy(); | ||
| 183 | |||
| 184 | return core->dequeue(); | ||
| 185 | } | ||
| 186 | |||
| 187 | virtual int getSize() const | ||
| 188 | { | ||
| 189 | return core->getSize(); | ||
| 190 | } | ||
| 191 | |||
| 192 | virtual value &peek() | ||
| 193 | { | ||
| 194 | _hardCopy(); | ||
| 195 | |||
| 196 | return core->get( 0 ); | ||
| 197 | } | ||
| 198 | |||
| 199 | virtual const value &peek() const | ||
| 200 | { | ||
| 201 | return core->get( 0 ); | ||
| 202 | } | ||
| 203 | |||
| 204 | value &operator[]( int iIndex ) | ||
| 205 | { | ||
| 206 | _hardCopy(); | ||
| 207 | |||
| 208 | return core->get( iIndex ); | ||
| 209 | } | ||
| 210 | |||
| 211 | protected: | ||
| 212 | virtual Core *_copyCore( Core *src ) | ||
| 213 | { | ||
| 214 | Core *pRet = _allocateCore(); | ||
| 215 | |||
| 216 | pRet->init( src->iCapacity ); | ||
| 217 | int iSize = src->getSize(); | ||
| 218 | for( int j = 0; j < iSize; j++ ) | ||
| 219 | { | ||
| 220 | pRet->enqueue( src->get( j ) ); | ||
| 221 | } | ||
| 222 | |||
| 223 | return pRet; | ||
| 224 | } | ||
| 104 | }; | 225 | }; |
| 105 | } | 226 | } |
| 106 | 227 | ||
diff --git a/src/server.cpp b/src/server.cpp index 51c056a..e701a69 100644 --- a/src/server.cpp +++ b/src/server.cpp | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | #include "bu/server.h" | 8 | #include "bu/server.h" |
| 9 | #include <errno.h> | 9 | #include <errno.h> |
| 10 | #include <unistd.h> | 10 | #include <unistd.h> |
| 11 | #include "bu/serversocket.h" | 11 | #include "bu/tcpserversocket.h" |
| 12 | #include "bu/client.h" | 12 | #include "bu/client.h" |
| 13 | #include "bu/socket.h" | 13 | #include "bu/tcpsocket.h" |
| 14 | #include "bu/config.h" | 14 | #include "bu/config.h" |
| 15 | 15 | ||
| 16 | Bu::Server::Server() : | 16 | Bu::Server::Server() : |
| @@ -28,7 +28,7 @@ Bu::Server::~Server() | |||
| 28 | 28 | ||
| 29 | void Bu::Server::addPort( int nPort, int nPoolSize ) | 29 | void Bu::Server::addPort( int nPort, int nPoolSize ) |
| 30 | { | 30 | { |
| 31 | ServerSocket *s = new ServerSocket( nPort, nPoolSize ); | 31 | TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize ); |
| 32 | int nSocket = s->getSocket(); | 32 | int nSocket = s->getSocket(); |
| 33 | FD_SET( nSocket, &fdActive ); | 33 | FD_SET( nSocket, &fdActive ); |
| 34 | hServers.insert( nSocket, s ); | 34 | hServers.insert( nSocket, s ); |
| @@ -36,7 +36,7 @@ void Bu::Server::addPort( int nPort, int nPoolSize ) | |||
| 36 | 36 | ||
| 37 | void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize ) | 37 | void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize ) |
| 38 | { | 38 | { |
| 39 | ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); | 39 | TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize ); |
| 40 | int nSocket = s->getSocket(); | 40 | int nSocket = s->getSocket(); |
| 41 | FD_SET( nSocket, &fdActive ); | 41 | FD_SET( nSocket, &fdActive ); |
| 42 | hServers.insert( nSocket, s ); | 42 | hServers.insert( nSocket, s ); |
| @@ -75,7 +75,7 @@ void Bu::Server::scan() | |||
| 75 | { | 75 | { |
| 76 | if( hServers.has( j ) ) | 76 | if( hServers.has( j ) ) |
| 77 | { | 77 | { |
| 78 | ServerSocket *pSrv = hServers.get( j ); | 78 | TcpServerSocket *pSrv = hServers.get( j ); |
| 79 | addClient( pSrv->accept(), pSrv->getPort() ); | 79 | addClient( pSrv->accept(), pSrv->getPort() ); |
| 80 | } | 80 | } |
| 81 | else | 81 | else |
| @@ -97,7 +97,7 @@ void Bu::Server::scan() | |||
| 97 | { | 97 | { |
| 98 | pClient->processOutput(); | 98 | pClient->processOutput(); |
| 99 | } | 99 | } |
| 100 | catch( Bu::SocketException &e ) | 100 | catch( Bu::TcpSocketException &e ) |
| 101 | { | 101 | { |
| 102 | closeClient( j ); | 102 | closeClient( j ); |
| 103 | } | 103 | } |
| @@ -136,7 +136,7 @@ void Bu::Server::addClient( int nSocket, int nPort ) | |||
| 136 | FD_SET( nSocket, &fdActive ); | 136 | FD_SET( nSocket, &fdActive ); |
| 137 | 137 | ||
| 138 | Client *c = new Client( | 138 | Client *c = new Client( |
| 139 | new Bu::Socket( nSocket ), | 139 | new Bu::TcpSocket( nSocket ), |
| 140 | new SrvClientLinkFactory() | 140 | new SrvClientLinkFactory() |
| 141 | ); | 141 | ); |
| 142 | hClients.insert( nSocket, c ); | 142 | hClients.insert( nSocket, c ); |
diff --git a/src/server.h b/src/server.h index 74ee99a..d6726fd 100644 --- a/src/server.h +++ b/src/server.h | |||
| @@ -25,8 +25,8 @@ | |||
| 25 | 25 | ||
| 26 | namespace Bu | 26 | namespace Bu |
| 27 | { | 27 | { |
| 28 | class ServerSocket; | 28 | class TcpServerSocket; |
| 29 | class Socket; | 29 | class TcpSocket; |
| 30 | class Client; | 30 | class Client; |
| 31 | 31 | ||
| 32 | /** | 32 | /** |
| @@ -97,7 +97,7 @@ namespace Bu | |||
| 97 | int nTimeoutSec; | 97 | int nTimeoutSec; |
| 98 | int nTimeoutUSec; | 98 | int nTimeoutUSec; |
| 99 | fd_set fdActive; | 99 | fd_set fdActive; |
| 100 | typedef Hash<int,ServerSocket *> SrvHash; | 100 | typedef Hash<int,TcpServerSocket *> SrvHash; |
| 101 | SrvHash hServers; | 101 | SrvHash hServers; |
| 102 | typedef Hash<int,Client *> ClientHash; | 102 | typedef Hash<int,Client *> ClientHash; |
| 103 | ClientHash hClients; | 103 | ClientHash hClients; |
| @@ -24,17 +24,10 @@ namespace Bu | |||
| 24 | { | 24 | { |
| 25 | subExceptionDecl( SetException ) | 25 | subExceptionDecl( SetException ) |
| 26 | 26 | ||
| 27 | template<typename T> | ||
| 28 | uint32_t __calcHashCode( const T &k ); | ||
| 29 | |||
| 30 | template<typename T> | ||
| 31 | bool __cmpHashKeys( const T &a, const T &b ); | ||
| 32 | |||
| 33 | template<typename key, typename sizecalc = struct __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename challoc = std::allocator<uint32_t> > | ||
| 34 | class Set; | ||
| 35 | |||
| 36 | /** | 27 | /** |
| 37 | * Libbu Template Set | 28 | *@todo Set should be rewritten, possibly using a b-tree as ordered storage |
| 29 | * in the backend. It should use either a b-tree or array for storage and | ||
| 30 | * allow set intersections, unions, etc. | ||
| 38 | *@param key (typename) The datatype of the hashtable keys | 31 | *@param key (typename) The datatype of the hashtable keys |
| 39 | *@param sizecalc (typename) Functor to compute new table size on rehash | 32 | *@param sizecalc (typename) Functor to compute new table size on rehash |
| 40 | *@param keyalloc (typename) Memory allocator for hashtable keys | 33 | *@param keyalloc (typename) Memory allocator for hashtable keys |
| @@ -45,754 +38,7 @@ namespace Bu | |||
| 45 | class Set | 38 | class Set |
| 46 | { | 39 | { |
| 47 | public: | 40 | public: |
| 48 | Set() : | ||
| 49 | nCapacity( 11 ), | ||
| 50 | nFilled( 0 ), | ||
| 51 | nDeleted( 0 ), | ||
| 52 | bFilled( NULL ), | ||
| 53 | bDeleted( NULL ), | ||
| 54 | aKeys( NULL ), | ||
| 55 | aHashCodes( NULL ) | ||
| 56 | { | ||
| 57 | nKeysSize = bitsToBytes( nCapacity ); | ||
| 58 | bFilled = ca.allocate( nKeysSize ); | ||
| 59 | bDeleted = ca.allocate( nKeysSize ); | ||
| 60 | clearBits(); | ||
| 61 | |||
| 62 | aHashCodes = ca.allocate( nCapacity ); | ||
| 63 | aKeys = ka.allocate( nCapacity ); | ||
| 64 | } | ||
| 65 | |||
| 66 | Set( const Set &src ) : | ||
| 67 | nCapacity( src.nCapacity ), | ||
| 68 | nFilled( 0 ), | ||
| 69 | nDeleted( 0 ), | ||
| 70 | bFilled( NULL ), | ||
| 71 | bDeleted( NULL ), | ||
| 72 | aKeys( NULL ), | ||
| 73 | aHashCodes( NULL ) | ||
| 74 | { | ||
| 75 | nKeysSize = bitsToBytes( nCapacity ); | ||
| 76 | bFilled = ca.allocate( nKeysSize ); | ||
| 77 | bDeleted = ca.allocate( nKeysSize ); | ||
| 78 | clearBits(); | ||
| 79 | |||
| 80 | aHashCodes = ca.allocate( nCapacity ); | ||
| 81 | aKeys = ka.allocate( nCapacity ); | ||
| 82 | |||
| 83 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
| 84 | { | ||
| 85 | if( src.isFilled( j ) ) | ||
| 86 | { | ||
| 87 | insert( src.aKeys[j] ); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * Set assignment operator. Clears this hashtable and | ||
| 94 | * copies RH into it. | ||
| 95 | */ | ||
| 96 | Set &operator=( const Set &src ) | ||
| 97 | { | ||
| 98 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
| 99 | { | ||
| 100 | if( isFilled( j ) ) | ||
| 101 | if( !isDeleted( j ) ) | ||
| 102 | { | ||
| 103 | ka.destroy( &aKeys[j] ); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | ka.deallocate( aKeys, nCapacity ); | ||
| 107 | ca.deallocate( bFilled, nKeysSize ); | ||
| 108 | ca.deallocate( bDeleted, nKeysSize ); | ||
| 109 | ca.deallocate( aHashCodes, nCapacity ); | ||
| 110 | |||
| 111 | nFilled = 0; | ||
| 112 | nDeleted = 0; | ||
| 113 | nCapacity = src.nCapacity; | ||
| 114 | nKeysSize = bitsToBytes( nCapacity ); | ||
| 115 | bFilled = ca.allocate( nKeysSize ); | ||
| 116 | bDeleted = ca.allocate( nKeysSize ); | ||
| 117 | clearBits(); | ||
| 118 | |||
| 119 | aHashCodes = ca.allocate( nCapacity ); | ||
| 120 | aKeys = ka.allocate( nCapacity ); | ||
| 121 | |||
| 122 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
| 123 | { | ||
| 124 | if( src.isFilled( j ) ) | ||
| 125 | { | ||
| 126 | insert( src.aKeys[j] ); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | return *this; | ||
| 131 | } | ||
| 132 | |||
| 133 | virtual ~Set() | ||
| 134 | { | ||
| 135 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
| 136 | { | ||
| 137 | if( isFilled( j ) ) | ||
| 138 | if( !isDeleted( j ) ) | ||
| 139 | { | ||
| 140 | ka.destroy( &aKeys[j] ); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | ka.deallocate( aKeys, nCapacity ); | ||
| 144 | ca.deallocate( bFilled, nKeysSize ); | ||
| 145 | ca.deallocate( bDeleted, nKeysSize ); | ||
| 146 | ca.deallocate( aHashCodes, nCapacity ); | ||
| 147 | } | ||
| 148 | |||
| 149 | /** | ||
| 150 | * Get the current hash table capacity. (Changes at re-hash) | ||
| 151 | *@returns (uint32_t) The current capacity. | ||
| 152 | */ | ||
| 153 | uint32_t getCapacity() | ||
| 154 | { | ||
| 155 | return nCapacity; | ||
| 156 | } | ||
| 157 | |||
| 158 | /** | ||
| 159 | * Get the number of hash locations spoken for. (Including | ||
| 160 | * not-yet-cleaned-up deleted items.) | ||
| 161 | *@returns (uint32_t) The current fill state. | ||
| 162 | */ | ||
| 163 | uint32_t getFill() | ||
| 164 | { | ||
| 165 | return nFilled; | ||
| 166 | } | ||
| 167 | |||
| 168 | /** | ||
| 169 | * Get the number of items stored in the hash table. | ||
| 170 | *@returns (uint32_t) The number of items stored in the hash table. | ||
| 171 | */ | ||
| 172 | uint32_t getSize() | ||
| 173 | { | ||
| 174 | return nFilled-nDeleted; | ||
| 175 | } | ||
| 176 | |||
| 177 | /** | ||
| 178 | * Get the number of items which have been deleted, but not yet | ||
| 179 | * cleaned up. | ||
| 180 | *@returns (uint32_t) The number of deleted items. | ||
| 181 | */ | ||
| 182 | uint32_t getDeleted() | ||
| 183 | { | ||
| 184 | return nDeleted; | ||
| 185 | } | ||
| 186 | |||
| 187 | /** | ||
| 188 | * Insert key (k) into the set | ||
| 189 | *@param k (key_type) Key to list the value under. | ||
| 190 | */ | ||
| 191 | virtual void insert( key k ) | ||
| 192 | { | ||
| 193 | uint32_t hash = __calcHashCode( k ); | ||
| 194 | bool bFill; | ||
| 195 | uint32_t nPos = probe( hash, k, bFill ); | ||
| 196 | |||
| 197 | if( bFill ) | ||
| 198 | { | ||
| 199 | onUpdate(); | ||
| 200 | } | ||
| 201 | else | ||
| 202 | { | ||
| 203 | fill( nPos, k, hash ); | ||
| 204 | onInsert(); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | /** | ||
| 209 | * Remove a value from the hash table. | ||
| 210 | *@param k (key_type) The data under this key will be erased. | ||
| 211 | */ | ||
| 212 | virtual void erase( key k ) | ||
| 213 | { | ||
| 214 | uint32_t hash = __calcHashCode( k ); | ||
| 215 | bool bFill; | ||
| 216 | uint32_t nPos = probe( hash, k, bFill ); | ||
| 217 | |||
| 218 | if( bFill ) | ||
| 219 | { | ||
| 220 | _erase( nPos ); | ||
| 221 | onDelete(); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | struct iterator; | ||
| 226 | |||
| 227 | /** | ||
| 228 | * Remove a value from the hash pointed to from an iterator. | ||
| 229 | *@param i (iterator &) The data to be erased. | ||
| 230 | */ | ||
| 231 | virtual void erase( struct iterator &i ) | ||
| 232 | { | ||
| 233 | if( this != &i.hsh ) | ||
| 234 | throw SetException("This iterator didn't come from this Hash."); | ||
| 235 | if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) | ||
| 236 | { | ||
| 237 | _erase( i.nPos ); | ||
| 238 | onDelete(); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | /** | ||
| 243 | * Remove all data from the hash table. | ||
| 244 | */ | ||
| 245 | virtual void clear() | ||
| 246 | { | ||
| 247 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
| 248 | { | ||
| 249 | if( isFilled( j ) ) | ||
| 250 | if( !isDeleted( j ) ) | ||
| 251 | { | ||
| 252 | _erase( j ); | ||
| 253 | onDelete(); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | clearBits(); | ||
| 258 | } | ||
| 259 | |||
| 260 | /** | ||
| 261 | * Does the hash table contain an item under key (k). | ||
| 262 | *@param k (key_type) The key to check. | ||
| 263 | *@returns (bool) Whether there was an item in the hash under key (k). | ||
| 264 | */ | ||
| 265 | virtual bool has( key k ) | ||
| 266 | { | ||
| 267 | bool bFill; | ||
| 268 | probe( __calcHashCode( k ), k, bFill, false ); | ||
| 269 | |||
| 270 | return bFill; | ||
| 271 | } | ||
| 272 | |||
| 273 | /** | ||
| 274 | * Iteration structure for iterating through the hash. | ||
| 275 | */ | ||
| 276 | typedef struct iterator | ||
| 277 | { | ||
| 278 | friend class Set<key, sizecalc, keyalloc, challoc>; | ||
| 279 | private: | ||
| 280 | iterator( Set<key, sizecalc, keyalloc, challoc> &hsh ) : | ||
| 281 | hsh( hsh ), | ||
| 282 | nPos( 0 ), | ||
| 283 | bFinished( false ) | ||
| 284 | { | ||
| 285 | nPos = hsh.getFirstPos( bFinished ); | ||
| 286 | } | ||
| 287 | |||
| 288 | iterator( Set<key, sizecalc, keyalloc, challoc> &hsh, bool bDone ) : | ||
| 289 | hsh( hsh ), | ||
| 290 | nPos( 0 ), | ||
| 291 | bFinished( bDone ) | ||
| 292 | { | ||
| 293 | } | ||
| 294 | |||
| 295 | Set<key, sizecalc, keyalloc, challoc> &hsh; | ||
| 296 | uint32_t nPos; | ||
| 297 | bool bFinished; | ||
| 298 | |||
| 299 | public: | ||
| 300 | /** | ||
| 301 | * Iterator incrementation operator. Move the iterator forward. | ||
| 302 | */ | ||
| 303 | iterator operator++( int ) | ||
| 304 | { | ||
| 305 | if( bFinished == false ) | ||
| 306 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
| 307 | |||
| 308 | return *this; | ||
| 309 | } | ||
| 310 | |||
| 311 | /** | ||
| 312 | * Iterator incrementation operator. Move the iterator forward. | ||
| 313 | */ | ||
| 314 | iterator operator++() | ||
| 315 | { | ||
| 316 | if( bFinished == false ) | ||
| 317 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
| 318 | |||
| 319 | return *this; | ||
| 320 | } | ||
| 321 | |||
| 322 | /** | ||
| 323 | * Iterator equality comparison operator. Iterators the same? | ||
| 324 | */ | ||
| 325 | bool operator==( const iterator &oth ) const | ||
| 326 | { | ||
| 327 | if( bFinished != oth.bFinished ) | ||
| 328 | return false; | ||
| 329 | if( bFinished == true ) | ||
| 330 | { | ||
| 331 | return true; | ||
| 332 | } | ||
| 333 | else | ||
| 334 | { | ||
| 335 | if( oth.nPos == nPos ) | ||
| 336 | return true; | ||
| 337 | return false; | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | /** | ||
| 342 | * Iterator not equality comparison operator. Not the same? | ||
| 343 | */ | ||
| 344 | bool operator!=( const iterator &oth ) const | ||
| 345 | { | ||
| 346 | return !(*this == oth ); | ||
| 347 | } | ||
| 348 | |||
| 349 | /** | ||
| 350 | * Iterator assignment operator. | ||
| 351 | */ | ||
| 352 | iterator operator=( const iterator &oth ) | ||
| 353 | { | ||
| 354 | if( &hsh != &oth.hsh ) | ||
| 355 | throw SetException( | ||
| 356 | "Cannot mix iterators from different set objects."); | ||
| 357 | nPos = oth.nPos; | ||
| 358 | bFinished = oth.bFinished; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * Iterator dereference operator... err.. get the value | ||
| 363 | *@returns (value_type &) The value behind this iterator. | ||
| 364 | */ | ||
| 365 | key &operator *() | ||
| 366 | { | ||
| 367 | return hsh.getKeyAtPos( nPos ); | ||
| 368 | } | ||
| 369 | |||
| 370 | const key &operator *() const | ||
| 371 | { | ||
| 372 | return hsh.getKeyAtPos( nPos ); | ||
| 373 | } | ||
| 374 | |||
| 375 | bool isValid() const | ||
| 376 | { | ||
| 377 | return !bFinished; | ||
| 378 | } | ||
| 379 | |||
| 380 | operator bool() const | ||
| 381 | { | ||
| 382 | return !bFinished; | ||
| 383 | } | ||
| 384 | } iterator; | ||
| 385 | |||
| 386 | /** | ||
| 387 | * Iteration structure for iterating through the set (const). | ||
| 388 | */ | ||
| 389 | typedef struct const_iterator | ||
| 390 | { | ||
| 391 | friend class Set<key, sizecalc, keyalloc, challoc>; | ||
| 392 | private: | ||
| 393 | const_iterator( const Set<key, sizecalc, keyalloc, challoc> &hsh ) : | ||
| 394 | hsh( hsh ), | ||
| 395 | nPos( 0 ), | ||
| 396 | bFinished( false ) | ||
| 397 | { | ||
| 398 | nPos = hsh.getFirstPos( bFinished ); | ||
| 399 | } | ||
| 400 | |||
| 401 | const_iterator( const Set<key, sizecalc, keyalloc, challoc> &hsh, bool bDone ) : | ||
| 402 | hsh( hsh ), | ||
| 403 | nPos( 0 ), | ||
| 404 | bFinished( bDone ) | ||
| 405 | { | ||
| 406 | } | ||
| 407 | |||
| 408 | const Set<key, sizecalc, keyalloc, challoc> &hsh; | ||
| 409 | uint32_t nPos; | ||
| 410 | bool bFinished; | ||
| 411 | |||
| 412 | public: | ||
| 413 | /** | ||
| 414 | * Iterator incrementation operator. Move the iterator forward. | ||
| 415 | */ | ||
| 416 | const_iterator operator++( int ) | ||
| 417 | { | ||
| 418 | if( bFinished == false ) | ||
| 419 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
| 420 | |||
| 421 | return *this; | ||
| 422 | } | ||
| 423 | |||
| 424 | /** | ||
| 425 | * Iterator incrementation operator. Move the iterator forward. | ||
| 426 | */ | ||
| 427 | const_iterator operator++() | ||
| 428 | { | ||
| 429 | if( bFinished == false ) | ||
| 430 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
| 431 | |||
| 432 | return *this; | ||
| 433 | } | ||
| 434 | |||
| 435 | /** | ||
| 436 | * Iterator equality comparison operator. Iterators the same? | ||
| 437 | */ | ||
| 438 | bool operator==( const const_iterator &oth ) const | ||
| 439 | { | ||
| 440 | if( bFinished != oth.bFinished ) | ||
| 441 | return false; | ||
| 442 | if( bFinished == true ) | ||
| 443 | { | ||
| 444 | return true; | ||
| 445 | } | ||
| 446 | else | ||
| 447 | { | ||
| 448 | if( oth.nPos == nPos ) | ||
| 449 | return true; | ||
| 450 | return false; | ||
| 451 | } | ||
| 452 | } | ||
| 453 | |||
| 454 | /** | ||
| 455 | * Iterator not equality comparison operator. Not the same? | ||
| 456 | */ | ||
| 457 | bool operator!=( const const_iterator &oth ) const | ||
| 458 | { | ||
| 459 | return !(*this == oth ); | ||
| 460 | } | ||
| 461 | |||
| 462 | /** | ||
| 463 | * Iterator assignment operator. | ||
| 464 | */ | ||
| 465 | const_iterator operator=( const const_iterator &oth ) | ||
| 466 | { | ||
| 467 | if( &hsh != &oth.hsh ) | ||
| 468 | throw SetException( | ||
| 469 | "Cannot mix iterators from different hash objects."); | ||
| 470 | nPos = oth.nPos; | ||
| 471 | bFinished = oth.bFinished; | ||
| 472 | } | ||
| 473 | |||
| 474 | /** | ||
| 475 | * Iterator dereference operator... err.. get the value | ||
| 476 | *@returns (value_type &) The value behind this iterator. | ||
| 477 | */ | ||
| 478 | const key &operator *() const | ||
| 479 | { | ||
| 480 | return hsh.getKeyAtPos( nPos ); | ||
| 481 | } | ||
| 482 | |||
| 483 | bool isValid() const | ||
| 484 | { | ||
| 485 | return !bFinished; | ||
| 486 | } | ||
| 487 | |||
| 488 | operator bool() const | ||
| 489 | { | ||
| 490 | return !bFinished; | ||
| 491 | } | ||
| 492 | } const_iterator; | ||
| 493 | |||
| 494 | /** | ||
| 495 | * Get an iterator pointing to the first item in the hash table. | ||
| 496 | *@returns (iterator) An iterator pointing to the first item in the | ||
| 497 | * hash table. | ||
| 498 | */ | ||
| 499 | iterator begin() | ||
| 500 | { | ||
| 501 | return iterator( *this ); | ||
| 502 | } | ||
| 503 | |||
| 504 | const_iterator begin() const | ||
| 505 | { | ||
| 506 | return const_iterator( *this ); | ||
| 507 | } | ||
| 508 | |||
| 509 | /** | ||
| 510 | * Get an iterator pointing to a point just past the last item in the | ||
| 511 | * hash table. | ||
| 512 | *@returns (iterator) An iterator pointing to a point just past the | ||
| 513 | * last item in the hash table. | ||
| 514 | */ | ||
| 515 | iterator end() | ||
| 516 | { | ||
| 517 | return iterator( *this, true ); | ||
| 518 | } | ||
| 519 | |||
| 520 | const_iterator end() const | ||
| 521 | { | ||
| 522 | return const_iterator( *this, true ); | ||
| 523 | } | ||
| 524 | |||
| 525 | /** | ||
| 526 | * Get a list of all the keys in the hash table. | ||
| 527 | *@returns (std::list<key_type>) The list of keys in the hash table. | ||
| 528 | */ | ||
| 529 | Bu::List<key> getKeys() const | ||
| 530 | { | ||
| 531 | Bu::List<key> lKeys; | ||
| 532 | |||
| 533 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
| 534 | { | ||
| 535 | if( isFilled( j ) ) | ||
| 536 | { | ||
| 537 | if( !isDeleted( j ) ) | ||
| 538 | { | ||
| 539 | lKeys.append( aKeys[j] ); | ||
| 540 | } | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | return lKeys; | ||
| 545 | } | ||
| 546 | |||
| 547 | protected: | ||
| 548 | virtual void onInsert() {} | ||
| 549 | virtual void onUpdate() {} | ||
| 550 | virtual void onDelete() {} | ||
| 551 | virtual void onReHash() {} | ||
| 552 | |||
| 553 | virtual void clearBits() | ||
| 554 | { | ||
| 555 | for( uint32_t j = 0; j < nKeysSize; j++ ) | ||
| 556 | { | ||
| 557 | bFilled[j] = bDeleted[j] = 0; | ||
| 558 | } | ||
| 559 | } | ||
| 560 | |||
| 561 | virtual void fill( uint32_t loc, key &k, uint32_t hash ) | ||
| 562 | { | ||
| 563 | bFilled[loc/32] |= (1<<(loc%32)); | ||
| 564 | ka.construct( &aKeys[loc], k ); | ||
| 565 | aHashCodes[loc] = hash; | ||
| 566 | nFilled++; | ||
| 567 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
| 568 | // nFilled, nDeleted, nCapacity ); | ||
| 569 | } | ||
| 570 | |||
| 571 | virtual void _erase( uint32_t loc ) | ||
| 572 | { | ||
| 573 | bDeleted[loc/32] |= (1<<(loc%32)); | ||
| 574 | ka.destroy( &aKeys[loc] ); | ||
| 575 | nDeleted++; | ||
| 576 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
| 577 | // nFilled, nDeleted, nCapacity ); | ||
| 578 | } | ||
| 579 | |||
| 580 | virtual key &getKeyAtPos( uint32_t nPos ) | ||
| 581 | { | ||
| 582 | return aKeys[nPos]; | ||
| 583 | } | ||
| 584 | |||
| 585 | virtual const key &getKeyAtPos( uint32_t nPos ) const | ||
| 586 | { | ||
| 587 | return aKeys[nPos]; | ||
| 588 | } | ||
| 589 | |||
| 590 | virtual uint32_t getFirstPos( bool &bFinished ) const | ||
| 591 | { | ||
| 592 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
| 593 | { | ||
| 594 | if( isFilled( j ) ) | ||
| 595 | if( !isDeleted( j ) ) | ||
| 596 | return j; | ||
| 597 | } | ||
| 598 | |||
| 599 | bFinished = true; | ||
| 600 | return 0; | ||
| 601 | } | ||
| 602 | |||
| 603 | virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const | ||
| 604 | { | ||
| 605 | for( uint32_t j = nPos+1; j < nCapacity; j++ ) | ||
| 606 | { | ||
| 607 | if( isFilled( j ) ) | ||
| 608 | if( !isDeleted( j ) ) | ||
| 609 | return j; | ||
| 610 | } | ||
| 611 | |||
| 612 | bFinished = true; | ||
| 613 | return 0; | ||
| 614 | } | ||
| 615 | |||
| 616 | uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) | ||
| 617 | { | ||
| 618 | uint32_t nCur = hash%nCapacity; | ||
| 619 | |||
| 620 | // First we scan to see if the key is already there, abort if we | ||
| 621 | // run out of probing room, or we find a non-filled entry | ||
| 622 | int8_t j; | ||
| 623 | for( j = 0; | ||
| 624 | isFilled( nCur ) && j < 32; | ||
| 625 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
| 626 | ) | ||
| 627 | { | ||
| 628 | // Is this the same hash code we were looking for? | ||
| 629 | if( hash == aHashCodes[nCur] ) | ||
| 630 | { | ||
| 631 | // Skip over deleted entries. Deleted entries are also filled, | ||
| 632 | // so we only have to do this check here. | ||
| 633 | if( isDeleted( nCur ) ) | ||
| 634 | continue; | ||
| 635 | |||
| 636 | // Is it really the same key? (for safety) | ||
| 637 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
| 638 | { | ||
| 639 | bFill = true; | ||
| 640 | return nCur; | ||
| 641 | } | ||
| 642 | } | ||
| 643 | } | ||
| 644 | |||
| 645 | // This is our insurance, if the table is full, then go ahead and | ||
| 646 | // rehash, then try again. | ||
| 647 | if( (isFilled( nCur ) || j == 32) && rehash == true ) | ||
| 648 | { | ||
| 649 | reHash( szCalc(getCapacity(), getFill(), getDeleted()) ); | ||
| 650 | |||
| 651 | // This is potentially dangerous, and could cause an infinite loop. | ||
| 652 | // Be careful writing probe, eh? | ||
| 653 | return probe( hash, k, bFill ); | ||
| 654 | } | ||
| 655 | |||
| 656 | bFill = false; | ||
| 657 | return nCur; | ||
| 658 | } | ||
| 659 | |||
| 660 | uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) const | ||
| 661 | { | ||
| 662 | uint32_t nCur = hash%nCapacity; | ||
| 663 | |||
| 664 | // First we scan to see if the key is already there, abort if we | ||
| 665 | // run out of probing room, or we find a non-filled entry | ||
| 666 | for( int8_t j = 0; | ||
| 667 | isFilled( nCur ) && j < 32; | ||
| 668 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
| 669 | ) | ||
| 670 | { | ||
| 671 | // Is this the same hash code we were looking for? | ||
| 672 | if( hash == aHashCodes[nCur] ) | ||
| 673 | { | ||
| 674 | // Skip over deleted entries. Deleted entries are also filled, | ||
| 675 | // so we only have to do this check here. | ||
| 676 | if( isDeleted( nCur ) ) | ||
| 677 | continue; | ||
| 678 | |||
| 679 | // Is it really the same key? (for safety) | ||
| 680 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
| 681 | { | ||
| 682 | bFill = true; | ||
| 683 | return nCur; | ||
| 684 | } | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | bFill = false; | ||
| 689 | return nCur; | ||
| 690 | } | ||
| 691 | |||
| 692 | void reHash( uint32_t nNewSize ) | ||
| 693 | { | ||
| 694 | //printf("---REHASH---"); | ||
| 695 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
| 696 | // nFilled, nDeleted, nCapacity ); | ||
| 697 | |||
| 698 | // Save all the old data | ||
| 699 | uint32_t nOldCapacity = nCapacity; | ||
| 700 | uint32_t *bOldFilled = bFilled; | ||
| 701 | uint32_t *aOldHashCodes = aHashCodes; | ||
| 702 | uint32_t nOldKeysSize = nKeysSize; | ||
| 703 | uint32_t *bOldDeleted = bDeleted; | ||
| 704 | key *aOldKeys = aKeys; | ||
| 705 | |||
| 706 | // Calculate new sizes | ||
| 707 | nCapacity = nNewSize; | ||
| 708 | nKeysSize = bitsToBytes( nCapacity ); | ||
| 709 | |||
| 710 | // Allocate new memory + prep | ||
| 711 | bFilled = ca.allocate( nKeysSize ); | ||
| 712 | bDeleted = ca.allocate( nKeysSize ); | ||
| 713 | clearBits(); | ||
| 714 | |||
| 715 | aHashCodes = ca.allocate( nCapacity ); | ||
| 716 | aKeys = ka.allocate( nCapacity ); | ||
| 717 | |||
| 718 | nDeleted = nFilled = 0; | ||
| 719 | |||
| 720 | // Re-insert all of the old data (except deleted items) | ||
| 721 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
| 722 | { | ||
| 723 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | ||
| 724 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
| 725 | { | ||
| 726 | insert( aOldKeys[j] ); | ||
| 727 | } | ||
| 728 | } | ||
| 729 | |||
| 730 | // Delete all of the old data | ||
| 731 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
| 732 | { | ||
| 733 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 ) | ||
| 734 | { | ||
| 735 | ka.destroy( &aOldKeys[j] ); | ||
| 736 | } | ||
| 737 | } | ||
| 738 | ka.deallocate( aOldKeys, nOldCapacity ); | ||
| 739 | ca.deallocate( bOldFilled, nOldKeysSize ); | ||
| 740 | ca.deallocate( bOldDeleted, nOldKeysSize ); | ||
| 741 | ca.deallocate( aOldHashCodes, nOldCapacity ); | ||
| 742 | } | ||
| 743 | |||
| 744 | virtual bool isFilled( uint32_t loc ) const | ||
| 745 | { | ||
| 746 | return (bFilled[loc/32]&(1<<(loc%32)))!=0; | ||
| 747 | } | ||
| 748 | |||
| 749 | virtual bool isDeleted( uint32_t loc ) const | ||
| 750 | { | ||
| 751 | return (bDeleted[loc/32]&(1<<(loc%32)))!=0; | ||
| 752 | } | ||
| 753 | |||
| 754 | protected: | ||
| 755 | uint32_t nCapacity; | ||
| 756 | uint32_t nFilled; | ||
| 757 | uint32_t nDeleted; | ||
| 758 | uint32_t *bFilled; | ||
| 759 | uint32_t *bDeleted; | ||
| 760 | uint32_t nKeysSize; | ||
| 761 | key *aKeys; | ||
| 762 | uint32_t *aHashCodes; | ||
| 763 | keyalloc ka; | ||
| 764 | challoc ca; | ||
| 765 | sizecalc szCalc; | ||
| 766 | }; | 41 | }; |
| 767 | |||
| 768 | template<typename key, typename b, typename c, typename d> | ||
| 769 | Archive &operator<<( Archive &ar, const Set<key, b, c, d> &h ) | ||
| 770 | { | ||
| 771 | ar << h.getSize(); | ||
| 772 | for( typename Set<key, b, c, d>::const_iterator i = h.begin(); i != h.end(); i++ ) | ||
| 773 | { | ||
| 774 | ar << (*i); | ||
| 775 | } | ||
| 776 | |||
| 777 | return ar; | ||
| 778 | } | ||
| 779 | |||
| 780 | template<typename key, typename b, typename c, typename d> | ||
| 781 | Archive &operator>>( Archive &ar, Set<key, b, c, d> &h ) | ||
| 782 | { | ||
| 783 | h.clear(); | ||
| 784 | long nSize; | ||
| 785 | ar >> nSize; | ||
| 786 | |||
| 787 | for( long j = 0; j < nSize; j++ ) | ||
| 788 | { | ||
| 789 | key v; | ||
| 790 | ar >> v; | ||
| 791 | h.insert( v ); | ||
| 792 | } | ||
| 793 | |||
| 794 | return ar; | ||
| 795 | } | ||
| 796 | } | 42 | } |
| 797 | 43 | ||
| 798 | #endif | 44 | #endif |
diff --git a/src/sharedcore.h b/src/sharedcore.h index 5a44df9..1887ca2 100644 --- a/src/sharedcore.h +++ b/src/sharedcore.h | |||
| @@ -15,10 +15,57 @@ | |||
| 15 | 15 | ||
| 16 | namespace Bu | 16 | namespace Bu |
| 17 | { | 17 | { |
| 18 | template<typename Core> | 18 | /** |
| 19 | * A mechanism for creating classes that perform lazy copies. The concept | ||
| 20 | * behind this is that instead of copying a large object when it is assigned | ||
| 21 | * or passed into a copy constructor we simply copy a pointer internally. | ||
| 22 | * The assumption is that many times when an object is passed by value we | ||
| 23 | * don't really want to keep the object around, we want the recipient to | ||
| 24 | * take ownership without allocating a new object. This allows that to | ||
| 25 | * happen. | ||
| 26 | * | ||
| 27 | * When used properly this makes object copying essentially free (O(1), | ||
| 28 | * that is) and performs the actual copy when a user tries to modify the | ||
| 29 | * object. | ||
| 30 | * | ||
| 31 | * For example, lets look at something like the getKeys function in | ||
| 32 | * Bu::Hash. When this function is called it creates a Bu::List of | ||
| 33 | * appropriate type, fills it with keys, and returns it. This is a good | ||
| 34 | * way for this function to behave, there may be additional issues if the | ||
| 35 | * List object were allocated with new and not on the stack. However, | ||
| 36 | * returning the List at the end of the function could potentially take | ||
| 37 | * a very long time depending on the size of the list and the type of the | ||
| 38 | * key. In this case the getKeys function doesn't want ownership of the | ||
| 39 | * List object, and when it returns it, it's local copy will be destroyed. | ||
| 40 | * | ||
| 41 | * However, List inherits from SharedCore, which means that when it is | ||
| 42 | * returned all we do is copy a pointer to the "core" of the list, which | ||
| 43 | * is a very fast operatorion. For a brief moment, before anyone can do | ||
| 44 | * anything else, there are two objects referencing the core of that single | ||
| 45 | * list. However, the getKeys() function will destroy it's local copy | ||
| 46 | * before the calling function can use it's new copy. That means that by | ||
| 47 | * the time the calling function can use it's new List of keys it is the | ||
| 48 | * only one with a reference to the core, and no copy will need to happen. | ||
| 49 | * | ||
| 50 | * Using SharedCore on your own classes is fairly straight forward. There | ||
| 51 | * are only a couple of steps. First, break the class into two classes. | ||
| 52 | * Move every variable from the original class (generally everything that's | ||
| 53 | * private) into the new class. Then make the original class inherit from | ||
| 54 | * SharedCore. The SharedCore template takes 2 parameters, first is the | ||
| 55 | * class it's inheriting from, second is the new core class. Now, in your | ||
| 56 | * original class you will have one class variable, a pointer named core. | ||
| 57 | * All of your original variables will be accessable through core. The next | ||
| 58 | * step is to access everything you used to through core, and to find | ||
| 59 | * every function that may change data in the core. At the top of every | ||
| 60 | * function that may change data you want to call _hardCopy(). | ||
| 61 | * | ||
| 62 | * That's more or less it. A more detailed guide will be written soon. | ||
| 63 | * @todo Write a guide for this. | ||
| 64 | */ | ||
| 65 | template<typename Shell, typename Core> | ||
| 19 | class SharedCore | 66 | class SharedCore |
| 20 | { | 67 | { |
| 21 | typedef class SharedCore<Core> _SharedType; | 68 | typedef class SharedCore<Shell, Core> _SharedType; |
| 22 | public: | 69 | public: |
| 23 | SharedCore() : | 70 | SharedCore() : |
| 24 | core( NULL ), | 71 | core( NULL ), |
| @@ -54,6 +101,18 @@ namespace Bu | |||
| 54 | return *iRefCount; | 101 | return *iRefCount; |
| 55 | } | 102 | } |
| 56 | 103 | ||
| 104 | Shell clone() const | ||
| 105 | { | ||
| 106 | Shell s( dynamic_cast<const Shell &>(*this) ); | ||
| 107 | s._hardCopy(); | ||
| 108 | return s; | ||
| 109 | } | ||
| 110 | |||
| 111 | bool isCoreShared( const Shell &rOther ) const | ||
| 112 | { | ||
| 113 | return rOther.core == core; | ||
| 114 | } | ||
| 115 | |||
| 57 | protected: | 116 | protected: |
| 58 | Core *core; | 117 | Core *core; |
| 59 | void _hardCopy() | 118 | void _hardCopy() |
| @@ -68,6 +127,20 @@ namespace Bu | |||
| 68 | iRefCount = new int( 1 ); | 127 | iRefCount = new int( 1 ); |
| 69 | } | 128 | } |
| 70 | 129 | ||
| 130 | /** | ||
| 131 | * Reset core acts like a hard copy, except instead of providing a | ||
| 132 | * standalone copy of the shared core, it provides a brand new core. | ||
| 133 | * | ||
| 134 | * Very useful in functions used to reset the state of an object. | ||
| 135 | */ | ||
| 136 | void _resetCore() | ||
| 137 | { | ||
| 138 | if( core ) | ||
| 139 | _deref(); | ||
| 140 | core = _allocateCore(); | ||
| 141 | iRefCount = new int( 1 ); | ||
| 142 | } | ||
| 143 | |||
| 71 | virtual Core *_allocateCore() | 144 | virtual Core *_allocateCore() |
| 72 | { | 145 | { |
| 73 | return new Core(); | 146 | return new Core(); |
diff --git a/src/serversocket.cpp b/src/tcpserversocket.cpp index 87d0035..7d7f6e4 100644 --- a/src/serversocket.cpp +++ b/src/tcpserversocket.cpp | |||
| @@ -21,13 +21,13 @@ | |||
| 21 | #include <sys/types.h> | 21 | #include <sys/types.h> |
| 22 | //#include <termios.h> | 22 | //#include <termios.h> |
| 23 | #include <fcntl.h> | 23 | #include <fcntl.h> |
| 24 | #include "bu/serversocket.h" | 24 | #include "bu/tcpserversocket.h" |
| 25 | 25 | ||
| 26 | #include "bu/config.h" | 26 | #include "bu/config.h" |
| 27 | 27 | ||
| 28 | namespace Bu { subExceptionDef( ServerSocketException ) } | 28 | namespace Bu { subExceptionDef( TcpServerSocketException ) } |
| 29 | 29 | ||
| 30 | Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) : | 30 | Bu::TcpServerSocket::TcpServerSocket( int nPort, int nPoolSize ) : |
| 31 | nPort( nPort ) | 31 | nPort( nPort ) |
| 32 | { | 32 | { |
| 33 | #ifdef WIN32 | 33 | #ifdef WIN32 |
| @@ -48,7 +48,7 @@ Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) : | |||
| 48 | startServer( name, nPoolSize ); | 48 | startServer( name, nPoolSize ); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) : | 51 | Bu::TcpServerSocket::TcpServerSocket(const FString &sAddr,int nPort, int nPoolSize) : |
| 52 | nPort( nPort ) | 52 | nPort( nPort ) |
| 53 | { | 53 | { |
| 54 | #ifdef WIN32 | 54 | #ifdef WIN32 |
| @@ -72,7 +72,7 @@ Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) : | |||
| 72 | startServer( name, nPoolSize ); | 72 | startServer( name, nPoolSize ); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | Bu::ServerSocket::ServerSocket( int nServer, bool bInit, int nPoolSize ) : | 75 | Bu::TcpServerSocket::TcpServerSocket( int nServer, bool bInit, int nPoolSize ) : |
| 76 | nServer( nServer ), | 76 | nServer( nServer ), |
| 77 | nPort( 0 ) | 77 | nPort( 0 ) |
| 78 | { | 78 | { |
| @@ -95,7 +95,7 @@ Bu::ServerSocket::ServerSocket( int nServer, bool bInit, int nPoolSize ) : | |||
| 95 | } | 95 | } |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | Bu::ServerSocket::ServerSocket( const ServerSocket &rSrc ) | 98 | Bu::TcpServerSocket::TcpServerSocket( const TcpServerSocket &rSrc ) |
| 99 | { | 99 | { |
| 100 | #ifdef WIN32 | 100 | #ifdef WIN32 |
| 101 | Bu::Winsock2::getInstance(); | 101 | Bu::Winsock2::getInstance(); |
| @@ -107,20 +107,20 @@ Bu::ServerSocket::ServerSocket( const ServerSocket &rSrc ) | |||
| 107 | FD_SET( nServer, &fdActive ); | 107 | FD_SET( nServer, &fdActive ); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | Bu::ServerSocket::~ServerSocket() | 110 | Bu::TcpServerSocket::~TcpServerSocket() |
| 111 | { | 111 | { |
| 112 | if( nServer > -1 ) | 112 | if( nServer > -1 ) |
| 113 | ::close( nServer ); | 113 | ::close( nServer ); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) | 116 | void Bu::TcpServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) |
| 117 | { | 117 | { |
| 118 | /* Create the socket. */ | 118 | /* Create the socket. */ |
| 119 | nServer = bu_socket( PF_INET, SOCK_STREAM, 0 ); | 119 | nServer = bu_socket( PF_INET, SOCK_STREAM, 0 ); |
| 120 | 120 | ||
| 121 | if( nServer < 0 ) | 121 | if( nServer < 0 ) |
| 122 | { | 122 | { |
| 123 | throw Bu::ServerSocketException("Couldn't create a listen socket."); | 123 | throw Bu::TcpServerSocketException("Couldn't create a listen socket."); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | int opt = 1; | 126 | int opt = 1; |
| @@ -135,16 +135,16 @@ void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) | |||
| 135 | initServer( name, nPoolSize ); | 135 | initServer( name, nPoolSize ); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | void Bu::ServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) | 138 | void Bu::TcpServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) |
| 139 | { | 139 | { |
| 140 | if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) | 140 | if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) |
| 141 | { | 141 | { |
| 142 | throw Bu::ServerSocketException("Couldn't bind to the listen socket."); | 142 | throw Bu::TcpServerSocketException("Couldn't bind to the listen socket."); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | if( bu_listen( nServer, nPoolSize ) < 0 ) | 145 | if( bu_listen( nServer, nPoolSize ) < 0 ) |
| 146 | { | 146 | { |
| 147 | throw Bu::ServerSocketException( | 147 | throw Bu::TcpServerSocketException( |
| 148 | "Couldn't begin listening to the server socket." | 148 | "Couldn't begin listening to the server socket." |
| 149 | ); | 149 | ); |
| 150 | } | 150 | } |
| @@ -154,12 +154,12 @@ void Bu::ServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) | |||
| 154 | FD_SET( nServer, &fdActive ); | 154 | FD_SET( nServer, &fdActive ); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | int Bu::ServerSocket::getSocket() | 157 | int Bu::TcpServerSocket::getSocket() |
| 158 | { | 158 | { |
| 159 | return nServer; | 159 | return nServer; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | 162 | int Bu::TcpServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) |
| 163 | { | 163 | { |
| 164 | fd_set fdRead = fdActive; | 164 | fd_set fdRead = fdActive; |
| 165 | 165 | ||
| @@ -171,7 +171,7 @@ int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | |||
| 171 | if( TEMP_FAILURE_RETRY( | 171 | if( TEMP_FAILURE_RETRY( |
| 172 | bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) | 172 | bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) |
| 173 | { | 173 | { |
| 174 | throw Bu::ServerSocketException( | 174 | throw Bu::TcpServerSocketException( |
| 175 | "Error scanning for new connections: %s", strerror( errno ) | 175 | "Error scanning for new connections: %s", strerror( errno ) |
| 176 | ); | 176 | ); |
| 177 | } | 177 | } |
| @@ -200,7 +200,7 @@ int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | |||
| 200 | #endif /* WIN32 */ | 200 | #endif /* WIN32 */ |
| 201 | if( nClient < 0 ) | 201 | if( nClient < 0 ) |
| 202 | { | 202 | { |
| 203 | throw Bu::ServerSocketException( | 203 | throw Bu::TcpServerSocketException( |
| 204 | "Error accepting a new connection: %s", strerror( errno ) | 204 | "Error accepting a new connection: %s", strerror( errno ) |
| 205 | ); | 205 | ); |
| 206 | } | 206 | } |
| @@ -219,7 +219,7 @@ int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | |||
| 219 | flags |= O_NONBLOCK; | 219 | flags |= O_NONBLOCK; |
| 220 | if( fcntl( nClient, F_SETFL, flags ) < 0) | 220 | if( fcntl( nClient, F_SETFL, flags ) < 0) |
| 221 | { | 221 | { |
| 222 | throw Bu::ServerSocketException( | 222 | throw Bu::TcpServerSocketException( |
| 223 | "Error setting option on client socket: %s", | 223 | "Error setting option on client socket: %s", |
| 224 | strerror( errno ) | 224 | strerror( errno ) |
| 225 | ); | 225 | ); |
| @@ -242,7 +242,7 @@ int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | |||
| 242 | return -1; | 242 | return -1; |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | int Bu::ServerSocket::getPort() | 245 | int Bu::TcpServerSocket::getPort() |
| 246 | { | 246 | { |
| 247 | return nPort; | 247 | return nPort; |
| 248 | } | 248 | } |
diff --git a/src/serversocket.h b/src/tcpserversocket.h index ee357a4..b1d7e02 100644 --- a/src/serversocket.h +++ b/src/tcpserversocket.h | |||
| @@ -5,8 +5,8 @@ | |||
| 5 | * terms of the license contained in the file LICENSE. | 5 | * terms of the license contained in the file LICENSE. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #ifndef BU_SERVER_SOCKET_H | 8 | #ifndef BU_TCP_SERVER_SOCKET_H |
| 9 | #define BU_SERVER_SOCKET_H | 9 | #define BU_TCP_SERVER_SOCKET_H |
| 10 | 10 | ||
| 11 | #include <stdint.h> | 11 | #include <stdint.h> |
| 12 | #include "bu/fstring.h" | 12 | #include "bu/fstring.h" |
| @@ -20,7 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | namespace Bu | 21 | namespace Bu |
| 22 | { | 22 | { |
| 23 | subExceptionDecl( ServerSocketException ); | 23 | subExceptionDecl( TcpServerSocketException ); |
| 24 | 24 | ||
| 25 | /** | 25 | /** |
| 26 | * A single tcp/ip server socket. When created the server socket will bind | 26 | * A single tcp/ip server socket. When created the server socket will bind |
| @@ -34,14 +34,14 @@ namespace Bu | |||
| 34 | * | 34 | * |
| 35 | *@ingroup Serving | 35 | *@ingroup Serving |
| 36 | */ | 36 | */ |
| 37 | class ServerSocket | 37 | class TcpServerSocket |
| 38 | { | 38 | { |
| 39 | public: | 39 | public: |
| 40 | ServerSocket( int nPort, int nPoolSize=40 ); | 40 | TcpServerSocket( int nPort, int nPoolSize=40 ); |
| 41 | ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); | 41 | TcpServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); |
| 42 | ServerSocket( int nSocket, bool bInit, int nPoolSize=40 ); | 42 | TcpServerSocket( int nSocket, bool bInit, int nPoolSize=40 ); |
| 43 | ServerSocket( const ServerSocket &rSrc ); | 43 | TcpServerSocket( const TcpServerSocket &rSrc ); |
| 44 | virtual ~ServerSocket(); | 44 | virtual ~TcpServerSocket(); |
| 45 | 45 | ||
| 46 | int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); | 46 | int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); |
| 47 | int getSocket(); | 47 | int getSocket(); |
diff --git a/src/socket.cpp b/src/tcpsocket.cpp index baf3be3..bbd9cf5 100644 --- a/src/socket.cpp +++ b/src/tcpsocket.cpp | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | #include <sys/time.h> | 14 | #include <sys/time.h> |
| 15 | #include <errno.h> | 15 | #include <errno.h> |
| 16 | #include <fcntl.h> | 16 | #include <fcntl.h> |
| 17 | #include "bu/socket.h" | 17 | #include "bu/tcpsocket.h" |
| 18 | 18 | ||
| 19 | #include "bu/config.h" | 19 | #include "bu/config.h" |
| 20 | 20 | ||
| @@ -29,10 +29,10 @@ | |||
| 29 | 29 | ||
| 30 | #define RBS (1024*2) | 30 | #define RBS (1024*2) |
| 31 | 31 | ||
| 32 | namespace Bu { subExceptionDef( SocketException ) } | 32 | namespace Bu { subExceptionDef( TcpSocketException ) } |
| 33 | 33 | ||
| 34 | Bu::Socket::Socket( int nSocket ) : | 34 | Bu::TcpSocket::TcpSocket( int nTcpSocket ) : |
| 35 | nSocket( nSocket ), | 35 | nTcpSocket( nTcpSocket ), |
| 36 | bActive( true ), | 36 | bActive( true ), |
| 37 | bBlocking( true ) | 37 | bBlocking( true ) |
| 38 | { | 38 | { |
| @@ -42,8 +42,9 @@ Bu::Socket::Socket( int nSocket ) : | |||
| 42 | setAddress(); | 42 | setAddress(); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | 45 | Bu::TcpSocket::TcpSocket( const Bu::FString &sAddr, int nPort, int nTimeout, |
| 46 | nSocket( 0 ), | 46 | bool bBlocking ) : |
| 47 | nTcpSocket( 0 ), | ||
| 47 | bActive( false ), | 48 | bActive( false ), |
| 48 | bBlocking( true ) | 49 | bBlocking( true ) |
| 49 | { | 50 | { |
| @@ -52,9 +53,9 @@ Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | |||
| 52 | #endif | 53 | #endif |
| 53 | 54 | ||
| 54 | /* Create the socket. */ | 55 | /* Create the socket. */ |
| 55 | nSocket = bu_socket( PF_INET, SOCK_STREAM, 0 ); | 56 | nTcpSocket = bu_socket( PF_INET, SOCK_STREAM, 0 ); |
| 56 | 57 | ||
| 57 | if( nSocket < 0 ) | 58 | if( nTcpSocket < 0 ) |
| 58 | { | 59 | { |
| 59 | throw ExceptionBase("Couldn't create socket.\n"); | 60 | throw ExceptionBase("Couldn't create socket.\n"); |
| 60 | } | 61 | } |
| @@ -78,12 +79,12 @@ Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | |||
| 78 | sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 ) | 79 | sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 ) |
| 79 | { | 80 | { |
| 80 | close(); | 81 | close(); |
| 81 | throw Bu::SocketException("Couldn't resolve hostname %s (%s).\n", | 82 | throw Bu::TcpSocketException("Couldn't resolve hostname %s (%s).\n", |
| 82 | sAddr.getStr(), bu_gai_strerror(ret)); | 83 | sAddr.getStr(), bu_gai_strerror(ret)); |
| 83 | } | 84 | } |
| 84 | 85 | ||
| 85 | bu_connect( | 86 | bu_connect( |
| 86 | nSocket, | 87 | nTcpSocket, |
| 87 | pAddr->ai_addr, | 88 | pAddr->ai_addr, |
| 88 | pAddr->ai_addrlen | 89 | pAddr->ai_addrlen |
| 89 | ); | 90 | ); |
| @@ -101,17 +102,17 @@ Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | |||
| 101 | int retval; | 102 | int retval; |
| 102 | 103 | ||
| 103 | FD_ZERO(&rfds); | 104 | FD_ZERO(&rfds); |
| 104 | FD_SET(nSocket, &rfds); | 105 | FD_SET(nTcpSocket, &rfds); |
| 105 | FD_ZERO(&wfds); | 106 | FD_ZERO(&wfds); |
| 106 | FD_SET(nSocket, &wfds); | 107 | FD_SET(nTcpSocket, &wfds); |
| 107 | FD_ZERO(&efds); | 108 | FD_ZERO(&efds); |
| 108 | FD_SET(nSocket, &efds); | 109 | FD_SET(nTcpSocket, &efds); |
| 109 | 110 | ||
| 110 | struct timeval tv; | 111 | struct timeval tv; |
| 111 | tv.tv_sec = nTimeout; | 112 | tv.tv_sec = nTimeout; |
| 112 | tv.tv_usec = 0; | 113 | tv.tv_usec = 0; |
| 113 | 114 | ||
| 114 | retval = bu_select( nSocket+1, &rfds, &wfds, &efds, &tv ); | 115 | retval = bu_select( nTcpSocket+1, &rfds, &wfds, &efds, &tv ); |
| 115 | 116 | ||
| 116 | if( retval == 0 ) | 117 | if( retval == 0 ) |
| 117 | { | 118 | { |
| @@ -120,51 +121,54 @@ Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | |||
| 120 | } | 121 | } |
| 121 | read( NULL, 0 ); // See if we can get any errors out of the way early. | 122 | read( NULL, 0 ); // See if we can get any errors out of the way early. |
| 122 | } | 123 | } |
| 124 | |||
| 125 | if( bBlocking ) | ||
| 126 | setBlocking( bBlocking ); | ||
| 123 | } | 127 | } |
| 124 | 128 | ||
| 125 | Bu::Socket::~Socket() | 129 | Bu::TcpSocket::~TcpSocket() |
| 126 | { | 130 | { |
| 127 | close(); | 131 | close(); |
| 128 | } | 132 | } |
| 129 | 133 | ||
| 130 | void Bu::Socket::close() | 134 | void Bu::TcpSocket::close() |
| 131 | { | 135 | { |
| 132 | if( bActive ) | 136 | if( bActive ) |
| 133 | { | 137 | { |
| 134 | #ifndef WIN32 | 138 | #ifndef WIN32 |
| 135 | fsync( nSocket ); | 139 | fsync( nTcpSocket ); |
| 136 | #endif | 140 | #endif |
| 137 | #ifdef WIN32 | 141 | #ifdef WIN32 |
| 138 | #ifndef SHUT_RDWR | 142 | #ifndef SHUT_RDWR |
| 139 | #define SHUT_RDWR (SD_BOTH) | 143 | #define SHUT_RDWR (SD_BOTH) |
| 140 | #endif | 144 | #endif |
| 141 | #endif | 145 | #endif |
| 142 | bu_shutdown( nSocket, SHUT_RDWR ); | 146 | bu_shutdown( nTcpSocket, SHUT_RDWR ); |
| 143 | ::close( nSocket ); | 147 | ::close( nTcpSocket ); |
| 144 | } | 148 | } |
| 145 | bActive = false; | 149 | bActive = false; |
| 146 | } | 150 | } |
| 147 | 151 | ||
| 148 | size_t Bu::Socket::read( void *pBuf, size_t nBytes ) | 152 | size_t Bu::TcpSocket::read( void *pBuf, size_t nBytes ) |
| 149 | { | 153 | { |
| 150 | fd_set rfds; | 154 | fd_set rfds; |
| 151 | FD_ZERO(&rfds); | 155 | FD_ZERO(&rfds); |
| 152 | FD_SET(nSocket, &rfds); | 156 | FD_SET(nTcpSocket, &rfds); |
| 153 | struct timeval tv = {0, 0}; | 157 | struct timeval tv = {0, 0}; |
| 154 | if( bu_select( nSocket+1, &rfds, NULL, NULL, &tv ) < 0 ) | 158 | if( bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ) < 0 ) |
| 155 | { | 159 | { |
| 156 | int iErr = errno; | 160 | int iErr = errno; |
| 157 | close(); | 161 | close(); |
| 158 | throw SocketException( SocketException::cRead, strerror(iErr) ); | 162 | throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) ); |
| 159 | } | 163 | } |
| 160 | if( FD_ISSET( nSocket, &rfds ) || bBlocking ) | 164 | if( FD_ISSET( nTcpSocket, &rfds ) || bBlocking ) |
| 161 | { | 165 | { |
| 162 | int nRead = TEMP_FAILURE_RETRY( | 166 | int nRead = TEMP_FAILURE_RETRY( |
| 163 | bu_recv( nSocket, (char *) pBuf, nBytes, 0 ) ); | 167 | bu_recv( nTcpSocket, (char *) pBuf, nBytes, 0 ) ); |
| 164 | if( nRead == 0 ) | 168 | if( nRead == 0 ) |
| 165 | { | 169 | { |
| 166 | close(); | 170 | close(); |
| 167 | throw SocketException( SocketException::cClosed, "Socket closed."); | 171 | throw TcpSocketException( TcpSocketException::cClosed, "TcpSocket closed."); |
| 168 | } | 172 | } |
| 169 | if( nRead < 0 ) | 173 | if( nRead < 0 ) |
| 170 | { | 174 | { |
| @@ -176,14 +180,14 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes ) | |||
| 176 | if( errno == ENETRESET || errno == ECONNRESET ) | 180 | if( errno == ENETRESET || errno == ECONNRESET ) |
| 177 | { | 181 | { |
| 178 | close(); | 182 | close(); |
| 179 | throw SocketException( SocketException::cClosed, | 183 | throw TcpSocketException( TcpSocketException::cClosed, |
| 180 | strerror(errno) ); | 184 | strerror(errno) ); |
| 181 | } | 185 | } |
| 182 | if( errno == EAGAIN ) | 186 | if( errno == EAGAIN ) |
| 183 | return 0; | 187 | return 0; |
| 184 | int iErr = errno; | 188 | int iErr = errno; |
| 185 | close(); | 189 | close(); |
| 186 | throw SocketException( SocketException::cRead, strerror(iErr) ); | 190 | throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) ); |
| 187 | #endif | 191 | #endif |
| 188 | } | 192 | } |
| 189 | return nRead; | 193 | return nRead; |
| @@ -191,7 +195,7 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes ) | |||
| 191 | return 0; | 195 | return 0; |
| 192 | } | 196 | } |
| 193 | 197 | ||
| 194 | size_t Bu::Socket::read( void *pBuf, size_t nBytes, | 198 | size_t Bu::TcpSocket::read( void *pBuf, size_t nBytes, |
| 195 | uint32_t nSec, uint32_t nUSec ) | 199 | uint32_t nSec, uint32_t nUSec ) |
| 196 | { | 200 | { |
| 197 | struct timeval tv; | 201 | struct timeval tv; |
| @@ -199,7 +203,7 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes, | |||
| 199 | 203 | ||
| 200 | fd_set rfds; | 204 | fd_set rfds; |
| 201 | FD_ZERO(&rfds); | 205 | FD_ZERO(&rfds); |
| 202 | FD_SET(nSocket, &rfds); | 206 | FD_SET(nTcpSocket, &rfds); |
| 203 | 207 | ||
| 204 | #ifdef WIN32 | 208 | #ifdef WIN32 |
| 205 | DWORD dwStart = GetTickCount(); | 209 | DWORD dwStart = GetTickCount(); |
| @@ -216,7 +220,7 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes, | |||
| 216 | { | 220 | { |
| 217 | tv.tv_sec = nSec; | 221 | tv.tv_sec = nSec; |
| 218 | tv.tv_usec = nUSec; | 222 | tv.tv_usec = nUSec; |
| 219 | bu_select( nSocket+1, &rfds, NULL, NULL, &tv ); | 223 | bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ); |
| 220 | nRead += read( ((char *)pBuf)+nRead, nBytes-nRead ); | 224 | nRead += read( ((char *)pBuf)+nRead, nBytes-nRead ); |
| 221 | if( nRead >= nBytes ) | 225 | if( nRead >= nBytes ) |
| 222 | break; | 226 | break; |
| @@ -235,13 +239,13 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes, | |||
| 235 | return nRead; | 239 | return nRead; |
| 236 | } | 240 | } |
| 237 | 241 | ||
| 238 | size_t Bu::Socket::write( const void *pBuf, size_t nBytes ) | 242 | size_t Bu::TcpSocket::write( const void *pBuf, size_t nBytes ) |
| 239 | { | 243 | { |
| 240 | //#ifdef WIN32 | 244 | //#ifdef WIN32 |
| 241 | int nWrote = TEMP_FAILURE_RETRY( | 245 | int nWrote = TEMP_FAILURE_RETRY( |
| 242 | bu_send( nSocket, (const char *) pBuf, nBytes, 0 ) ); | 246 | bu_send( nTcpSocket, (const char *) pBuf, nBytes, 0 ) ); |
| 243 | //#else | 247 | //#else |
| 244 | // int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) ); | 248 | // int nWrote = TEMP_FAILURE_RETRY( ::write( nTcpSocket, pBuf, nBytes ) ); |
| 245 | //#endif | 249 | //#endif |
| 246 | if( nWrote < 0 ) | 250 | if( nWrote < 0 ) |
| 247 | { | 251 | { |
| @@ -252,19 +256,19 @@ size_t Bu::Socket::write( const void *pBuf, size_t nBytes ) | |||
| 252 | #else | 256 | #else |
| 253 | if( errno == EAGAIN ) return 0; | 257 | if( errno == EAGAIN ) return 0; |
| 254 | #endif | 258 | #endif |
| 255 | throw SocketException( SocketException::cWrite, strerror(errno) ); | 259 | throw TcpSocketException( TcpSocketException::cWrite, strerror(errno) ); |
| 256 | } | 260 | } |
| 257 | return nWrote; | 261 | return nWrote; |
| 258 | } | 262 | } |
| 259 | 263 | ||
| 260 | size_t Bu::Socket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32_t nUSec ) | 264 | size_t Bu::TcpSocket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32_t nUSec ) |
| 261 | { | 265 | { |
| 262 | struct timeval tv; | 266 | struct timeval tv; |
| 263 | size_t nWrote = 0; | 267 | size_t nWrote = 0; |
| 264 | 268 | ||
| 265 | fd_set wfds; | 269 | fd_set wfds; |
| 266 | FD_ZERO(&wfds); | 270 | FD_ZERO(&wfds); |
| 267 | FD_SET(nSocket, &wfds); | 271 | FD_SET(nTcpSocket, &wfds); |
| 268 | 272 | ||
| 269 | #ifdef WIN32 | 273 | #ifdef WIN32 |
| 270 | DWORD dwStart = GetTickCount(); | 274 | DWORD dwStart = GetTickCount(); |
| @@ -281,7 +285,7 @@ size_t Bu::Socket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32 | |||
| 281 | { | 285 | { |
| 282 | tv.tv_sec = nSec; | 286 | tv.tv_sec = nSec; |
| 283 | tv.tv_usec = nUSec; | 287 | tv.tv_usec = nUSec; |
| 284 | bu_select( nSocket+1, NULL, &wfds, NULL, &tv ); | 288 | bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv ); |
| 285 | nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote ); | 289 | nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote ); |
| 286 | if( nWrote >= nBytes ) | 290 | if( nWrote >= nBytes ) |
| 287 | break; | 291 | break; |
| @@ -300,101 +304,101 @@ size_t Bu::Socket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32 | |||
| 300 | return nWrote; | 304 | return nWrote; |
| 301 | } | 305 | } |
| 302 | 306 | ||
| 303 | long Bu::Socket::tell() | 307 | long Bu::TcpSocket::tell() |
| 304 | { | 308 | { |
| 305 | throw UnsupportedException(); | 309 | throw UnsupportedException(); |
| 306 | } | 310 | } |
| 307 | 311 | ||
| 308 | void Bu::Socket::seek( long ) | 312 | void Bu::TcpSocket::seek( long ) |
| 309 | { | 313 | { |
| 310 | throw UnsupportedException(); | 314 | throw UnsupportedException(); |
| 311 | } | 315 | } |
| 312 | 316 | ||
| 313 | void Bu::Socket::setPos( long ) | 317 | void Bu::TcpSocket::setPos( long ) |
| 314 | { | 318 | { |
| 315 | throw UnsupportedException(); | 319 | throw UnsupportedException(); |
| 316 | } | 320 | } |
| 317 | 321 | ||
| 318 | void Bu::Socket::setPosEnd( long ) | 322 | void Bu::TcpSocket::setPosEnd( long ) |
| 319 | { | 323 | { |
| 320 | throw UnsupportedException(); | 324 | throw UnsupportedException(); |
| 321 | } | 325 | } |
| 322 | 326 | ||
| 323 | bool Bu::Socket::isEos() | 327 | bool Bu::TcpSocket::isEos() |
| 324 | { | 328 | { |
| 325 | return !bActive; | 329 | return !bActive; |
| 326 | } | 330 | } |
| 327 | 331 | ||
| 328 | bool Bu::Socket::canRead() | 332 | bool Bu::TcpSocket::canRead() |
| 329 | { | 333 | { |
| 330 | fd_set rfds; | 334 | fd_set rfds; |
| 331 | FD_ZERO(&rfds); | 335 | FD_ZERO(&rfds); |
| 332 | FD_SET(nSocket, &rfds); | 336 | FD_SET(nTcpSocket, &rfds); |
| 333 | struct timeval tv = { 0, 0 }; | 337 | struct timeval tv = { 0, 0 }; |
| 334 | int retval = bu_select( nSocket+1, &rfds, NULL, NULL, &tv ); | 338 | int retval = bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ); |
| 335 | if( retval == -1 ) | 339 | if( retval == -1 ) |
| 336 | throw SocketException( | 340 | throw TcpSocketException( |
| 337 | SocketException::cBadRead, | 341 | TcpSocketException::cBadRead, |
| 338 | "Bad Read error" | 342 | "Bad Read error" |
| 339 | ); | 343 | ); |
| 340 | 344 | ||
| 341 | if( !FD_ISSET( nSocket, &rfds ) ) | 345 | if( !FD_ISSET( nTcpSocket, &rfds ) ) |
| 342 | return false; | 346 | return false; |
| 343 | return true; | 347 | return true; |
| 344 | } | 348 | } |
| 345 | 349 | ||
| 346 | bool Bu::Socket::canWrite() | 350 | bool Bu::TcpSocket::canWrite() |
| 347 | { | 351 | { |
| 348 | fd_set wfds; | 352 | fd_set wfds; |
| 349 | FD_ZERO(&wfds); | 353 | FD_ZERO(&wfds); |
| 350 | FD_SET(nSocket, &wfds); | 354 | FD_SET(nTcpSocket, &wfds); |
| 351 | struct timeval tv = { 0, 0 }; | 355 | struct timeval tv = { 0, 0 }; |
| 352 | int retval = bu_select( nSocket+1, NULL, &wfds, NULL, &tv ); | 356 | int retval = bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv ); |
| 353 | if( retval == -1 ) | 357 | if( retval == -1 ) |
| 354 | throw SocketException( | 358 | throw TcpSocketException( |
| 355 | SocketException::cBadRead, | 359 | TcpSocketException::cBadRead, |
| 356 | "Bad Read error" | 360 | "Bad Read error" |
| 357 | ); | 361 | ); |
| 358 | if( !FD_ISSET( nSocket, &wfds ) ) | 362 | if( !FD_ISSET( nTcpSocket, &wfds ) ) |
| 359 | return false; | 363 | return false; |
| 360 | return true; | 364 | return true; |
| 361 | } | 365 | } |
| 362 | 366 | ||
| 363 | bool Bu::Socket::isReadable() | 367 | bool Bu::TcpSocket::isReadable() |
| 364 | { | 368 | { |
| 365 | return true; | 369 | return true; |
| 366 | } | 370 | } |
| 367 | 371 | ||
| 368 | bool Bu::Socket::isWritable() | 372 | bool Bu::TcpSocket::isWritable() |
| 369 | { | 373 | { |
| 370 | return true; | 374 | return true; |
| 371 | } | 375 | } |
| 372 | 376 | ||
| 373 | bool Bu::Socket::isSeekable() | 377 | bool Bu::TcpSocket::isSeekable() |
| 374 | { | 378 | { |
| 375 | return false; | 379 | return false; |
| 376 | } | 380 | } |
| 377 | 381 | ||
| 378 | bool Bu::Socket::isBlocking() | 382 | bool Bu::TcpSocket::isBlocking() |
| 379 | { | 383 | { |
| 380 | #ifndef WIN32 | 384 | #ifndef WIN32 |
| 381 | return ((fcntl( nSocket, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK); | 385 | return ((fcntl( nTcpSocket, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK); |
| 382 | #else | 386 | #else |
| 383 | return false; | 387 | return false; |
| 384 | #endif | 388 | #endif |
| 385 | } | 389 | } |
| 386 | 390 | ||
| 387 | void Bu::Socket::setBlocking( bool bBlocking ) | 391 | void Bu::TcpSocket::setBlocking( bool bBlocking ) |
| 388 | { | 392 | { |
| 389 | this->bBlocking = bBlocking; | 393 | this->bBlocking = bBlocking; |
| 390 | #ifndef WIN32 | 394 | #ifndef WIN32 |
| 391 | if( bBlocking ) | 395 | if( bBlocking ) |
| 392 | { | 396 | { |
| 393 | fcntl( nSocket, F_SETFL, fcntl( nSocket, F_GETFL, 0 ) & (~O_NONBLOCK) ); | 397 | fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) & (~O_NONBLOCK) ); |
| 394 | } | 398 | } |
| 395 | else | 399 | else |
| 396 | { | 400 | { |
| 397 | fcntl( nSocket, F_SETFL, fcntl( nSocket, F_GETFL, 0 ) | O_NONBLOCK ); | 401 | fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) | O_NONBLOCK ); |
| 398 | } | 402 | } |
| 399 | #else | 403 | #else |
| 400 | u_long iMode; | 404 | u_long iMode; |
| @@ -408,39 +412,39 @@ void Bu::Socket::setBlocking( bool bBlocking ) | |||
| 408 | // socket based on the numerical value of iMode. | 412 | // socket based on the numerical value of iMode. |
| 409 | // If iMode = 0, blocking is enabled; | 413 | // If iMode = 0, blocking is enabled; |
| 410 | // If iMode != 0, non-blocking mode is enabled. | 414 | // If iMode != 0, non-blocking mode is enabled. |
| 411 | bu_ioctlsocket(nSocket, FIONBIO, &iMode); | 415 | bu_ioctlsocket(nTcpSocket, FIONBIO, &iMode); |
| 412 | #endif | 416 | #endif |
| 413 | } | 417 | } |
| 414 | 418 | ||
| 415 | void Bu::Socket::setSize( long ) | 419 | void Bu::TcpSocket::setSize( long ) |
| 416 | { | 420 | { |
| 417 | } | 421 | } |
| 418 | 422 | ||
| 419 | void Bu::Socket::flush() | 423 | void Bu::TcpSocket::flush() |
| 420 | { | 424 | { |
| 421 | } | 425 | } |
| 422 | 426 | ||
| 423 | bool Bu::Socket::isOpen() | 427 | bool Bu::TcpSocket::isOpen() |
| 424 | { | 428 | { |
| 425 | return bActive; | 429 | return bActive; |
| 426 | } | 430 | } |
| 427 | 431 | ||
| 428 | void Bu::Socket::setAddress() | 432 | void Bu::TcpSocket::setAddress() |
| 429 | { | 433 | { |
| 430 | struct sockaddr_in addr; | 434 | struct sockaddr_in addr; |
| 431 | socklen_t len = sizeof(addr); | 435 | socklen_t len = sizeof(addr); |
| 432 | addr.sin_family = AF_INET; | 436 | addr.sin_family = AF_INET; |
| 433 | bu_getpeername( nSocket, (sockaddr *)(&addr), &len ); | 437 | bu_getpeername( nTcpSocket, (sockaddr *)(&addr), &len ); |
| 434 | sAddress = bu_inet_ntoa( addr.sin_addr ); | 438 | sAddress = bu_inet_ntoa( addr.sin_addr ); |
| 435 | } | 439 | } |
| 436 | 440 | ||
| 437 | Bu::FString Bu::Socket::getAddress() const | 441 | Bu::FString Bu::TcpSocket::getAddress() const |
| 438 | { | 442 | { |
| 439 | return sAddress; | 443 | return sAddress; |
| 440 | } | 444 | } |
| 441 | 445 | ||
| 442 | Bu::Socket::operator int() const | 446 | Bu::TcpSocket::operator int() const |
| 443 | { | 447 | { |
| 444 | return nSocket; | 448 | return nTcpSocket; |
| 445 | } | 449 | } |
| 446 | 450 | ||
diff --git a/src/socket.h b/src/tcpsocket.h index c8f78f0..3361e84 100644 --- a/src/socket.h +++ b/src/tcpsocket.h | |||
| @@ -5,8 +5,8 @@ | |||
| 5 | * terms of the license contained in the file LICENSE. | 5 | * terms of the license contained in the file LICENSE. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #ifndef BU_SOCKET_H | 8 | #ifndef BU_TCP_SOCKET_H |
| 9 | #define BU_SOCKET_H | 9 | #define BU_TCP_SOCKET_H |
| 10 | 10 | ||
| 11 | #include <stdint.h> | 11 | #include <stdint.h> |
| 12 | 12 | ||
| @@ -16,7 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | namespace Bu | 17 | namespace Bu |
| 18 | { | 18 | { |
| 19 | subExceptionDeclBegin( SocketException ); | 19 | subExceptionDeclBegin( TcpSocketException ); |
| 20 | enum { | 20 | enum { |
| 21 | cRead, | 21 | cRead, |
| 22 | cWrite, | 22 | cWrite, |
| @@ -40,28 +40,29 @@ namespace Bu | |||
| 40 | * Please note that there is a condition that will occur eventually (at | 40 | * Please note that there is a condition that will occur eventually (at |
| 41 | * least on *nix systems) that will trigger a SIGPIPE condition. This | 41 | * least on *nix systems) that will trigger a SIGPIPE condition. This |
| 42 | * will terminate your program immediately unless handled properly. Most | 42 | * will terminate your program immediately unless handled properly. Most |
| 43 | * people doing any connections with Socket will want to put this in their | 43 | * people doing any connections with TcpSocket will want to put this in |
| 44 | * program somewhere before they use it: | 44 | * their program somewhere before they use it: |
| 45 | *@code | 45 | *@code |
| 46 | #include <signal.h> | 46 | #include <signal.h> |
| 47 | ... | 47 | ... |
| 48 | ... | 48 | ... |
| 49 | ... | 49 | ... |
| 50 | sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::Socket | 50 | sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::TcpSocket |
| 51 | @endcode | 51 | @endcode |
| 52 | * When this is done, Bu::Socket will simply throw a broken pipe exception | 52 | * When this is done, Bu::TcpSocket will simply throw a broken pipe |
| 53 | * just like every other error condition, allowing your program to handle | 53 | * exception just like every other error condition, allowing your program |
| 54 | * it sanely. | 54 | * to handle it sanely. |
| 55 | * | 55 | * |
| 56 | *@ingroup Serving | 56 | *@ingroup Serving |
| 57 | *@ingroup Streams | 57 | *@ingroup Streams |
| 58 | */ | 58 | */ |
| 59 | class Socket : public Stream | 59 | class TcpSocket : public Stream |
| 60 | { | 60 | { |
| 61 | public: | 61 | public: |
| 62 | Socket( int nSocket ); | 62 | TcpSocket( int nTcpSocket ); |
| 63 | Socket( const FString &sAddr, int nPort, int nTimeout=30 ); | 63 | TcpSocket( const FString &sAddr, int nPort, int nTimeout=30, |
| 64 | virtual ~Socket(); | 64 | bool bBlocking=true ); |
| 65 | virtual ~TcpSocket(); | ||
| 65 | 66 | ||
| 66 | virtual void close(); | 67 | virtual void close(); |
| 67 | //virtual void read(); | 68 | //virtual void read(); |
| @@ -101,9 +102,9 @@ namespace Bu | |||
| 101 | void setAddress(); | 102 | void setAddress(); |
| 102 | 103 | ||
| 103 | #ifdef WIN32 | 104 | #ifdef WIN32 |
| 104 | unsigned int nSocket; | 105 | unsigned int nTcpSocket; |
| 105 | #else | 106 | #else |
| 106 | int nSocket; | 107 | int nTcpSocket; |
| 107 | #endif | 108 | #endif |
| 108 | bool bActive; | 109 | bool bActive; |
| 109 | bool bBlocking; | 110 | bool bBlocking; |
diff --git a/src/tests/sharedcore.cpp b/src/tests/sharedcore.cpp index 1d0c16e..9b0a0ec 100644 --- a/src/tests/sharedcore.cpp +++ b/src/tests/sharedcore.cpp | |||
| @@ -14,7 +14,7 @@ struct ShintCore | |||
| 14 | { | 14 | { |
| 15 | int val; | 15 | int val; |
| 16 | }; | 16 | }; |
| 17 | class Shint : public Bu::SharedCore<struct ShintCore> | 17 | class Shint : public Bu::SharedCore<Shint, struct ShintCore> |
| 18 | { | 18 | { |
| 19 | public: | 19 | public: |
| 20 | Shint() | 20 | Shint() |
diff --git a/src/tests/socketblock.cpp b/src/tests/socketblock.cpp index a1ea18d..793ef96 100644 --- a/src/tests/socketblock.cpp +++ b/src/tests/socketblock.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include "bu/ito.h" | 8 | #include "bu/ito.h" |
| 9 | #include "bu/socket.h" | 9 | #include "bu/tcpsocket.h" |
| 10 | #include "bu/serversocket.h" | 10 | #include "bu/tcpserversocket.h" |
| 11 | #include <stdio.h> | 11 | #include <stdio.h> |
| 12 | #include <unistd.h> | 12 | #include <unistd.h> |
| 13 | 13 | ||
| @@ -21,7 +21,7 @@ public: | |||
| 21 | 21 | ||
| 22 | virtual void run() | 22 | virtual void run() |
| 23 | { | 23 | { |
| 24 | Bu::Socket c = s.accept( 45, 0 ); | 24 | Bu::TcpSocket c = s.accept( 45, 0 ); |
| 25 | printf("TstServer: Accetped connection.\n"); fflush( stdout ); | 25 | printf("TstServer: Accetped connection.\n"); fflush( stdout ); |
| 26 | 26 | ||
| 27 | sleep( 1 ); | 27 | sleep( 1 ); |
| @@ -35,7 +35,7 @@ public: | |||
| 35 | c.close(); | 35 | c.close(); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | Bu::ServerSocket s; | 38 | Bu::TcpServerSocket s; |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | int main() | 41 | int main() |
| @@ -45,7 +45,7 @@ int main() | |||
| 45 | ts.start(); | 45 | ts.start(); |
| 46 | 46 | ||
| 47 | printf("main: Connecting to server.\n"); fflush( stdout ); | 47 | printf("main: Connecting to server.\n"); fflush( stdout ); |
| 48 | Bu::Socket s( "localhost", 55678 ); | 48 | Bu::TcpSocket s( "localhost", 55678 ); |
| 49 | 49 | ||
| 50 | printf("main: Sending 4 bytes.\n"); fflush( stdout ); | 50 | printf("main: Sending 4 bytes.\n"); fflush( stdout ); |
| 51 | s.write( "aoeu", 4 ); | 51 | s.write( "aoeu", 4 ); |
diff --git a/src/tests/socketbreak.cpp b/src/tests/socketbreak.cpp index 8339630..7d3c71a 100644 --- a/src/tests/socketbreak.cpp +++ b/src/tests/socketbreak.cpp | |||
| @@ -5,17 +5,17 @@ | |||
| 5 | * terms of the license contained in the file LICENSE. | 5 | * terms of the license contained in the file LICENSE. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include "bu/serversocket.h" | 8 | #include "bu/tcpserversocket.h" |
| 9 | #include "bu/socket.h" | 9 | #include "bu/tcpsocket.h" |
| 10 | #include <unistd.h> | 10 | #include <unistd.h> |
| 11 | 11 | ||
| 12 | int main() | 12 | int main() |
| 13 | { | 13 | { |
| 14 | Bu::ServerSocket sSrv( 9987 ); | 14 | Bu::TcpServerSocket sSrv( 9987 ); |
| 15 | 15 | ||
| 16 | Bu::Socket sSend("localhost", 9987 ); | 16 | Bu::TcpSocket sSend("localhost", 9987 ); |
| 17 | 17 | ||
| 18 | Bu::Socket sRecv( sSrv.accept() ); | 18 | Bu::TcpSocket sRecv( sSrv.accept() ); |
| 19 | 19 | ||
| 20 | printf("Connected sockets.\n"); | 20 | printf("Connected sockets.\n"); |
| 21 | 21 | ||
diff --git a/src/tests/socket.cpp b/src/tests/tcpsocket.cpp index ba4e9b9..30dd22f 100644 --- a/src/tests/socket.cpp +++ b/src/tests/tcpsocket.cpp | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | * terms of the license contained in the file LICENSE. | 5 | * terms of the license contained in the file LICENSE. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <bu/socket.h> | 8 | #include <bu/tcpsocket.h> |
| 9 | #include <bu/sio.h> | 9 | #include <bu/sio.h> |
| 10 | 10 | ||
| 11 | #include <sys/time.h> | 11 | #include <sys/time.h> |
| @@ -17,7 +17,7 @@ bool isUp() | |||
| 17 | { | 17 | { |
| 18 | try | 18 | try |
| 19 | { | 19 | { |
| 20 | Socket s("xagasoft.com", 9898, 1 ); | 20 | TcpSocket s("xagasoft.com", 9898, 1 ); |
| 21 | 21 | ||
| 22 | char buf[5]; | 22 | char buf[5]; |
| 23 | buf[s.read(buf, 2, 1, 0)] = '\0'; | 23 | buf[s.read(buf, 2, 1, 0)] = '\0'; |
diff --git a/src/tools/bnfcompile.cpp b/src/tools/bnfcompile.cpp new file mode 100644 index 0000000..16e75a5 --- /dev/null +++ b/src/tools/bnfcompile.cpp | |||
| @@ -0,0 +1,410 @@ | |||
| 1 | #include <bu/sio.h> | ||
| 2 | #include <bu/lexer.h> | ||
| 3 | #include <bu/parser.h> | ||
| 4 | #include <bu/file.h> | ||
| 5 | #include <bu/queuebuf.h> | ||
| 6 | |||
| 7 | using namespace Bu; | ||
| 8 | |||
| 9 | enum TokenType | ||
| 10 | { | ||
| 11 | tokIdentifier, | ||
| 12 | tokColon, | ||
| 13 | tokOr, | ||
| 14 | tokSemiColon, | ||
| 15 | tokTokens, | ||
| 16 | tokEquals, | ||
| 17 | tokOpenCurly, | ||
| 18 | tokCloseCurly, | ||
| 19 | tokOpenSquare, | ||
| 20 | tokCloseSquare, | ||
| 21 | |||
| 22 | tokEos=-1 | ||
| 23 | }; | ||
| 24 | |||
| 25 | class BnfLexer : public Lexer | ||
| 26 | { | ||
| 27 | public: | ||
| 28 | BnfLexer( Stream &rSrc ) : | ||
| 29 | rSrc( rSrc ) | ||
| 30 | { | ||
| 31 | } | ||
| 32 | |||
| 33 | virtual ~BnfLexer() | ||
| 34 | { | ||
| 35 | } | ||
| 36 | |||
| 37 | virtual Token *nextToken() | ||
| 38 | { | ||
| 39 | char cBuf; | ||
| 40 | |||
| 41 | for(;;) | ||
| 42 | { | ||
| 43 | if( qbIn.getSize() == 0 ) | ||
| 44 | { | ||
| 45 | char buf[4096]; | ||
| 46 | qbIn.write( buf, rSrc.read( buf, 4096 ) ); | ||
| 47 | |||
| 48 | if( rSrc.isEos() && qbIn.getSize() == 0 ) | ||
| 49 | return new Token( tokEos ); | ||
| 50 | } | ||
| 51 | qbIn.peek( &cBuf, 1 ); | ||
| 52 | if( (cBuf >= 'a' && cBuf <= 'z') || | ||
| 53 | (cBuf >= 'A' && cBuf <= 'Z') || | ||
| 54 | (cBuf >= '0' && cBuf <= '9') || | ||
| 55 | cBuf == '_' ) | ||
| 56 | { | ||
| 57 | sBuf.append( cBuf ); | ||
| 58 | qbIn.seek( 1 ); | ||
| 59 | } | ||
| 60 | else if( sBuf.isSet() ) | ||
| 61 | { | ||
| 62 | if( sBuf == "tokens" ) | ||
| 63 | { | ||
| 64 | sBuf.clear(); | ||
| 65 | return new Token( tokTokens ); | ||
| 66 | } | ||
| 67 | else | ||
| 68 | { | ||
| 69 | Token *pRet = new Token( tokIdentifier, sBuf ); | ||
| 70 | sBuf.clear(); | ||
| 71 | return pRet; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | else | ||
| 75 | { | ||
| 76 | switch( cBuf ) | ||
| 77 | { | ||
| 78 | case ' ': | ||
| 79 | case '\t': | ||
| 80 | case '\n': | ||
| 81 | case '\r': | ||
| 82 | qbIn.seek( 1 ); | ||
| 83 | continue; | ||
| 84 | |||
| 85 | case ':': | ||
| 86 | qbIn.seek( 1 ); | ||
| 87 | return new Token( tokColon ); | ||
| 88 | |||
| 89 | case ';': | ||
| 90 | qbIn.seek( 1 ); | ||
| 91 | return new Token( tokSemiColon ); | ||
| 92 | |||
| 93 | case '|': | ||
| 94 | qbIn.seek( 1 ); | ||
| 95 | return new Token( tokOr ); | ||
| 96 | |||
| 97 | case '=': | ||
| 98 | qbIn.seek( 1 ); | ||
| 99 | return new Token( tokEquals ); | ||
| 100 | |||
| 101 | case '[': | ||
| 102 | qbIn.seek( 1 ); | ||
| 103 | return new Token( tokOpenSquare ); | ||
| 104 | |||
| 105 | case ']': | ||
| 106 | qbIn.seek( 1 ); | ||
| 107 | return new Token( tokCloseSquare ); | ||
| 108 | |||
| 109 | case '{': | ||
| 110 | qbIn.seek( 1 ); | ||
| 111 | return new Token( tokOpenCurly ); | ||
| 112 | |||
| 113 | case '}': | ||
| 114 | qbIn.seek( 1 ); | ||
| 115 | return new Token( tokCloseCurly ); | ||
| 116 | |||
| 117 | default: | ||
| 118 | throw ExceptionBase("Unexpected character '%c'.", | ||
| 119 | cBuf ); | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | virtual FString tokenToString( const Token &t ) | ||
| 127 | { | ||
| 128 | switch( (TokenType)t.iToken ) | ||
| 129 | { | ||
| 130 | case tokIdentifier: return "tokIdentifier"; | ||
| 131 | case tokColon: return "tokColon"; | ||
| 132 | case tokOr: return "tokOr"; | ||
| 133 | case tokSemiColon: return "tokSemiColon"; | ||
| 134 | case tokTokens: return "tokTokens"; | ||
| 135 | case tokEquals: return "tokEquals"; | ||
| 136 | case tokOpenCurly: return "tokOpenCurly"; | ||
| 137 | case tokCloseCurly: return "tokCloseCurly"; | ||
| 138 | case tokOpenSquare: return "tokOpenSquare"; | ||
| 139 | case tokCloseSquare: return "tokCloseSquare"; | ||
| 140 | case tokEos: return "tokEos"; | ||
| 141 | } | ||
| 142 | |||
| 143 | return "???"; | ||
| 144 | } | ||
| 145 | |||
| 146 | private: | ||
| 147 | Stream &rSrc; | ||
| 148 | QueueBuf qbIn; | ||
| 149 | FString sBuf; | ||
| 150 | }; | ||
| 151 | |||
| 152 | class BnfParser | ||
| 153 | { | ||
| 154 | public: | ||
| 155 | BnfParser( BnfLexer &l ) : | ||
| 156 | l( l ), | ||
| 157 | pCur( NULL ), | ||
| 158 | iLastToken( 0 ) | ||
| 159 | { | ||
| 160 | } | ||
| 161 | |||
| 162 | virtual ~BnfParser() | ||
| 163 | { | ||
| 164 | delete pCur; | ||
| 165 | pCur = NULL; | ||
| 166 | } | ||
| 167 | |||
| 168 | void parse() | ||
| 169 | { | ||
| 170 | for(;;) | ||
| 171 | { | ||
| 172 | next(); | ||
| 173 | switch( pCur->iToken ) | ||
| 174 | { | ||
| 175 | case tokTokens: | ||
| 176 | tokens(); | ||
| 177 | break; | ||
| 178 | |||
| 179 | case tokIdentifier: | ||
| 180 | nonTerminal(); | ||
| 181 | break; | ||
| 182 | |||
| 183 | case tokEos: | ||
| 184 | return; | ||
| 185 | break; | ||
| 186 | |||
| 187 | default: | ||
| 188 | tokenError("tokTokens, tokIdentifier, or tokEos"); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | private: | ||
| 194 | void tokens() | ||
| 195 | { | ||
| 196 | next(); | ||
| 197 | if( pCur->iToken != tokEquals ) | ||
| 198 | tokenError("tokEquals"); | ||
| 199 | for(;;) | ||
| 200 | { | ||
| 201 | next(); | ||
| 202 | if( pCur->iToken == tokIdentifier ) | ||
| 203 | { | ||
| 204 | hTokens.insert( pCur->vExtra.get<Bu::FString>(), ++iLastToken ); | ||
| 205 | sio << "Added token[" << iLastToken << "]: " | ||
| 206 | << pCur->vExtra.get<Bu::FString>() << sio.nl; | ||
| 207 | } | ||
| 208 | else if( pCur->iToken == tokSemiColon ) | ||
| 209 | break; | ||
| 210 | else | ||
| 211 | tokenError("tokIdentifier or tokSemiColon"); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | void nonTerminal() | ||
| 216 | { | ||
| 217 | Bu::FString sNtName = pCur->vExtra.get<Bu::FString>(); | ||
| 218 | Parser::NonTerminal nt; | ||
| 219 | p.addNonTerminal( sNtName ); | ||
| 220 | sio.incIndent(); | ||
| 221 | sio << "Created non-terminal: " << sNtName << sio.nl; | ||
| 222 | |||
| 223 | next(); | ||
| 224 | if( pCur->iToken != tokColon ) | ||
| 225 | tokenError("tokColon"); | ||
| 226 | production( nt ); | ||
| 227 | for(;;) | ||
| 228 | { | ||
| 229 | switch( pCur->iToken ) | ||
| 230 | { | ||
| 231 | case tokOr: | ||
| 232 | production( nt ); | ||
| 233 | break; | ||
| 234 | |||
| 235 | case tokSemiColon: | ||
| 236 | p.setNonTerminal( sNtName, nt ); | ||
| 237 | sio.decIndent(); | ||
| 238 | sio << "Closing non-terminal." << sio.nl; | ||
| 239 | return; | ||
| 240 | |||
| 241 | default: | ||
| 242 | tokenError("tkOr or tokSemiColon"); | ||
| 243 | break; | ||
| 244 | } | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | void production( Parser::NonTerminal &nt ) | ||
| 249 | { | ||
| 250 | sio.incIndent(); | ||
| 251 | sio << "Adding new production:" << sio.nl; | ||
| 252 | Parser::Production pr; | ||
| 253 | bool bAnything = false; | ||
| 254 | for(;;) | ||
| 255 | { | ||
| 256 | next(); | ||
| 257 | switch( pCur->iToken ) | ||
| 258 | { | ||
| 259 | case tokIdentifier: | ||
| 260 | { | ||
| 261 | const Bu::FString &sName = | ||
| 262 | pCur->vExtra.get<Bu::FString>(); | ||
| 263 | if( hTokens.has( sName ) ) | ||
| 264 | { | ||
| 265 | pr.append( | ||
| 266 | Parser::State( | ||
| 267 | Parser::State::typeTerminal, | ||
| 268 | hTokens.get( sName ) | ||
| 269 | ) | ||
| 270 | ); | ||
| 271 | sio << "Added terminal " << sName << sio.nl; | ||
| 272 | } | ||
| 273 | else | ||
| 274 | { | ||
| 275 | if( !p.hasNonTerminal( sName ) ) | ||
| 276 | { | ||
| 277 | p.addNonTerminal( sName ); | ||
| 278 | } | ||
| 279 | pr.append( | ||
| 280 | Parser::State( | ||
| 281 | Parser::State::typeNonTerminal, | ||
| 282 | p.getNonTerminalId( sName ) | ||
| 283 | ) | ||
| 284 | ); | ||
| 285 | sio << "Added non-terminal " << sName << sio.nl; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | break; | ||
| 289 | |||
| 290 | case tokOpenSquare: | ||
| 291 | { | ||
| 292 | next(); | ||
| 293 | if( pCur->iToken != tokIdentifier ) | ||
| 294 | tokenError("tokIdentifier"); | ||
| 295 | Bu::FString sName = | ||
| 296 | pCur->vExtra.get<Bu::FString>(); | ||
| 297 | next(); | ||
| 298 | if( pCur->iToken != tokCloseSquare ) | ||
| 299 | tokenError("tokCloseSquare"); | ||
| 300 | |||
| 301 | if( !hTokens.has( sName ) ) | ||
| 302 | throw ExceptionBase("Only token names may be " | ||
| 303 | "enclosed in square brackets."); | ||
| 304 | |||
| 305 | pr.append( | ||
| 306 | Parser::State( | ||
| 307 | Parser::State::typeTerminalPush, | ||
| 308 | hTokens.get( sName ) | ||
| 309 | ) | ||
| 310 | ); | ||
| 311 | sio << "Added terminal-push " << sName << sio.nl; | ||
| 312 | } | ||
| 313 | break; | ||
| 314 | |||
| 315 | case tokOpenCurly: | ||
| 316 | { | ||
| 317 | next(); | ||
| 318 | if( pCur->iToken != tokIdentifier ) | ||
| 319 | tokenError("tokIdentifier"); | ||
| 320 | Bu::FString sName = | ||
| 321 | pCur->vExtra.get<Bu::FString>(); | ||
| 322 | next(); | ||
| 323 | if( pCur->iToken != tokCloseCurly ) | ||
| 324 | tokenError("tokCloseCurly"); | ||
| 325 | |||
| 326 | if( !p.hasReduction( sName ) ) | ||
| 327 | p.addReduction( sName ); | ||
| 328 | |||
| 329 | pr.append( | ||
| 330 | Parser::State( | ||
| 331 | Parser::State::typeReduction, | ||
| 332 | p.getReductionId( sName ) | ||
| 333 | ) | ||
| 334 | ); | ||
| 335 | sio << "Added reduction " << sName << sio.nl; | ||
| 336 | } | ||
| 337 | break; | ||
| 338 | |||
| 339 | case tokOr: | ||
| 340 | case tokSemiColon: | ||
| 341 | if( bAnything ) | ||
| 342 | { | ||
| 343 | nt.addProduction( pr ); | ||
| 344 | sio.decIndent(); | ||
| 345 | sio << "Closing production." << sio.nl; | ||
| 346 | } | ||
| 347 | else | ||
| 348 | { | ||
| 349 | nt.setCanSkip(); | ||
| 350 | sio.decIndent(); | ||
| 351 | sio << "Closing empty production." << sio.nl; | ||
| 352 | } | ||
| 353 | return; | ||
| 354 | |||
| 355 | default: | ||
| 356 | tokenError("tokIdentifier, tokOpenSquare, tokOr, " | ||
| 357 | "tokOpenCurly, or tokSemiColon"); | ||
| 358 | } | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | private: | ||
| 363 | void next() | ||
| 364 | { | ||
| 365 | delete pCur; | ||
| 366 | pCur = l.nextToken(); | ||
| 367 | } | ||
| 368 | |||
| 369 | void tokenError( const FString &s ) | ||
| 370 | { | ||
| 371 | throw ExceptionBase( ("Expected " + s + " but found " | ||
| 372 | + l.tokenToString( *pCur ) + ".").getStr() ); | ||
| 373 | } | ||
| 374 | |||
| 375 | private: | ||
| 376 | typedef Bu::Hash<Bu::FString, int> TokenHash; | ||
| 377 | TokenHash hTokens; | ||
| 378 | BnfLexer &l; | ||
| 379 | BnfLexer::Token *pCur; | ||
| 380 | int iLastToken; | ||
| 381 | Parser p; | ||
| 382 | }; | ||
| 383 | |||
| 384 | int main( int argc, char *argv[] ) | ||
| 385 | { | ||
| 386 | File fIn( argv[1], File::Read ); | ||
| 387 | |||
| 388 | BnfLexer bl( fIn ); | ||
| 389 | BnfParser parser( bl ); | ||
| 390 | |||
| 391 | parser.parse(); | ||
| 392 | |||
| 393 | /* | ||
| 394 | for(;;) | ||
| 395 | { | ||
| 396 | Lexer::Token *pTok = bl.nextToken(); | ||
| 397 | sio << bl.tokenToString(*pTok); | ||
| 398 | if( pTok->vExtra.isSet() ) | ||
| 399 | { | ||
| 400 | sio << " - " << pTok->vExtra; | ||
| 401 | } | ||
| 402 | sio << sio.nl; | ||
| 403 | if( pTok->iToken == tokEos ) | ||
| 404 | break; | ||
| 405 | } | ||
| 406 | */ | ||
| 407 | |||
| 408 | return 0; | ||
| 409 | } | ||
| 410 | |||
diff --git a/src/tools/myriadfs.cpp b/src/tools/myriadfs.cpp new file mode 100644 index 0000000..66955a5 --- /dev/null +++ b/src/tools/myriadfs.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | #define FUSE_USE_VERSION 26 | ||
| 2 | |||
| 3 | #include <fuse.h> | ||
| 4 | |||
| 5 | #include <string.h> | ||
| 6 | |||
| 7 | extern "C" { | ||
| 8 | static int myriadfs_getattr( const char *sPath, struct stat *stbuf ) | ||
| 9 | { | ||
| 10 | |||
| 11 | } | ||
| 12 | |||
| 13 | static int myriadfs_readdir( const char *sPath, void *buf, | ||
| 14 | fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi ) | ||
| 15 | { | ||
| 16 | } | ||
| 17 | |||
| 18 | static int myriadfs_open( const char *sPath, struct fuse_file_info *fi ) | ||
| 19 | { | ||
| 20 | } | ||
| 21 | |||
| 22 | static int myriadfs_read( const char *sPath, char *buf, size_t iSize, | ||
| 23 | off_t iOffset, struct fuse_file_info *fi ) | ||
| 24 | { | ||
| 25 | } | ||
| 26 | |||
| 27 | static struct fuse_operations myriadfs_oper; | ||
| 28 | |||
| 29 | int main( int argc, char *argv[] ) | ||
| 30 | { | ||
| 31 | memset( &myriadfs_oper, sizeof(myriadfs_oper), 0 ); | ||
| 32 | myriadfs_oper.getattr = myriadfs_getattr; | ||
| 33 | myriadfs_oper.readdir = myriadfs_readdir; | ||
| 34 | myriadfs_oper.open = myriadfs_open; | ||
| 35 | myriadfs_oper.read = myriadfs_read; | ||
| 36 | return fuse_main( argc, argv, &myriadfs_oper, NULL ); | ||
| 37 | } | ||
| 38 | } | ||
diff --git a/src/tools/parser.cpp b/src/tools/parser.cpp index 76d4a72..7933f31 100644 --- a/src/tools/parser.cpp +++ b/src/tools/parser.cpp | |||
| @@ -151,10 +151,43 @@ private: | |||
| 151 | 151 | ||
| 152 | void redAdd( Bu::Parser &p ) | 152 | void redAdd( Bu::Parser &p ) |
| 153 | { | 153 | { |
| 154 | Lexer::Token *a = p.popToken(); | ||
| 155 | Lexer::Token *b = p.popToken(); | ||
| 156 | |||
| 157 | sio << "Add! " << b->vExtra.get<double>() << " + " | ||
| 158 | << a->vExtra.get<double>() << sio.nl; | ||
| 159 | |||
| 160 | Lexer::Token *c = new Lexer::Token( tokNumber, | ||
| 161 | b->vExtra.get<double>() + a->vExtra.get<double>() | ||
| 162 | ); | ||
| 163 | p.pushToken( c ); | ||
| 164 | |||
| 165 | delete a; | ||
| 166 | delete b; | ||
| 167 | } | ||
| 168 | |||
| 169 | void redSubtract( Bu::Parser &p ) | ||
| 170 | { | ||
| 171 | Lexer::Token *a = p.popToken(); | ||
| 172 | Lexer::Token *b = p.popToken(); | ||
| 173 | |||
| 174 | sio << "Subtract! " << b->vExtra.get<double>() << " - " | ||
| 175 | << a->vExtra.get<double>() << sio.nl; | ||
| 176 | |||
| 177 | Lexer::Token *c = new Lexer::Token( tokNumber, | ||
| 178 | b->vExtra.get<double>() - a->vExtra.get<double>() | ||
| 179 | ); | ||
| 180 | p.pushToken( c ); | ||
| 181 | |||
| 182 | delete a; | ||
| 183 | delete b; | ||
| 154 | } | 184 | } |
| 155 | 185 | ||
| 156 | void redPrint( Bu::Parser &p ) | 186 | void redPrint( Bu::Parser &p ) |
| 157 | { | 187 | { |
| 188 | Lexer::Token *a = p.popToken(); | ||
| 189 | sio << "Print! = " << a->vExtra.get<double>() << sio.nl; | ||
| 190 | delete a; | ||
| 158 | } | 191 | } |
| 159 | 192 | ||
| 160 | /* Basic grammer example: | 193 | /* Basic grammer example: |
| @@ -170,14 +203,15 @@ void redPrint( Bu::Parser &p ) | |||
| 170 | * The problem is, that we can't actually make something left hand recursive, | 203 | * The problem is, that we can't actually make something left hand recursive, |
| 171 | * so we break it into two exprs: | 204 | * so we break it into two exprs: |
| 172 | * | 205 | * |
| 173 | * expr': '(' expr ')' | 206 | * expr-sub1: '(' expr ')' |
| 174 | * | NUMBER | 207 | * | NUMBER |
| 175 | * ; | 208 | * ; |
| 176 | * | 209 | * |
| 177 | * expr: expr' expr'' | 210 | * expr: expr-sub1 expr-sub2 |
| 178 | * ; | 211 | * ; |
| 179 | * | 212 | * |
| 180 | * expr'': '+' expr | 213 | * expr-sub2: '+' expr |
| 214 | * | '-' expr | ||
| 181 | * | | 215 | * | |
| 182 | * ; | 216 | * ; |
| 183 | * | 217 | * |
| @@ -191,8 +225,8 @@ int main( int argc, char *argv[] ) | |||
| 191 | Parser p; | 225 | Parser p; |
| 192 | 226 | ||
| 193 | p.addNonTerminal("expr"); | 227 | p.addNonTerminal("expr"); |
| 194 | p.addNonTerminal("expr'"); | 228 | p.addNonTerminal("expr-sub1"); |
| 195 | p.addNonTerminal("expr''"); | 229 | p.addNonTerminal("expr-sub2"); |
| 196 | { | 230 | { |
| 197 | Parser::NonTerminal nt; | 231 | Parser::NonTerminal nt; |
| 198 | nt.addProduction( | 232 | nt.addProduction( |
| @@ -215,10 +249,28 @@ int main( int argc, char *argv[] ) | |||
| 215 | ); | 249 | ); |
| 216 | nt.addProduction( | 250 | nt.addProduction( |
| 217 | Parser::Production( | 251 | Parser::Production( |
| 252 | Parser::State( | ||
| 253 | Parser::State::typeTerminal, | ||
| 254 | tokMinus | ||
| 255 | ) | ||
| 256 | ).append( | ||
| 257 | Parser::State( | ||
| 258 | Parser::State::typeNonTerminal, | ||
| 259 | p.getNonTerminalId("expr") | ||
| 260 | ) | ||
| 261 | ).append( | ||
| 262 | Parser::State( | ||
| 263 | Parser::State::typeReduction, | ||
| 264 | p.addReduction("subtract") | ||
| 265 | ) | ||
| 266 | ) | ||
| 267 | ); | ||
| 268 | nt.addProduction( | ||
| 269 | Parser::Production( | ||
| 218 | ) | 270 | ) |
| 219 | ); | 271 | ); |
| 220 | nt.setCanSkip(); | 272 | nt.setCanSkip(); |
| 221 | p.setNonTerminal("expr''", nt ); | 273 | p.setNonTerminal("expr-sub2", nt ); |
| 222 | } | 274 | } |
| 223 | { | 275 | { |
| 224 | Parser::NonTerminal nt; | 276 | Parser::NonTerminal nt; |
| @@ -230,7 +282,25 @@ int main( int argc, char *argv[] ) | |||
| 230 | ) | 282 | ) |
| 231 | ) | 283 | ) |
| 232 | ); | 284 | ); |
| 233 | p.setNonTerminal("expr'", nt ); | 285 | nt.addProduction( |
| 286 | Parser::Production( | ||
| 287 | Parser::State( | ||
| 288 | Parser::State::typeTerminal, | ||
| 289 | tokOpenParen | ||
| 290 | ) | ||
| 291 | ).append( | ||
| 292 | Parser::State( | ||
| 293 | Parser::State::typeNonTerminal, | ||
| 294 | p.getNonTerminalId("expr") | ||
| 295 | ) | ||
| 296 | ).append( | ||
| 297 | Parser::State( | ||
| 298 | Parser::State::typeTerminal, | ||
| 299 | tokCloseParen | ||
| 300 | ) | ||
| 301 | ) | ||
| 302 | ); | ||
| 303 | p.setNonTerminal("expr-sub1", nt ); | ||
| 234 | } | 304 | } |
| 235 | { | 305 | { |
| 236 | Parser::NonTerminal nt; | 306 | Parser::NonTerminal nt; |
| @@ -238,12 +308,12 @@ int main( int argc, char *argv[] ) | |||
| 238 | Parser::Production( | 308 | Parser::Production( |
| 239 | Parser::State( | 309 | Parser::State( |
| 240 | Parser::State::typeNonTerminal, | 310 | Parser::State::typeNonTerminal, |
| 241 | p.getNonTerminalId("expr'") | 311 | p.getNonTerminalId("expr-sub1") |
| 242 | ) | 312 | ) |
| 243 | ).append( | 313 | ).append( |
| 244 | Parser::State( | 314 | Parser::State( |
| 245 | Parser::State::typeNonTerminal, | 315 | Parser::State::typeNonTerminal, |
| 246 | p.getNonTerminalId("expr''") | 316 | p.getNonTerminalId("expr-sub2") |
| 247 | ) | 317 | ) |
| 248 | ) | 318 | ) |
| 249 | ); | 319 | ); |
| @@ -275,6 +345,7 @@ int main( int argc, char *argv[] ) | |||
| 275 | p.setRootNonTerminal("input"); | 345 | p.setRootNonTerminal("input"); |
| 276 | 346 | ||
| 277 | p.setReduction("add", Bu::slot( &redAdd ) ); | 347 | p.setReduction("add", Bu::slot( &redAdd ) ); |
| 348 | p.setReduction("subtract", Bu::slot( &redSubtract ) ); | ||
| 278 | p.setReduction("print", Bu::slot( &redPrint ) ); | 349 | p.setReduction("print", Bu::slot( &redPrint ) ); |
| 279 | 350 | ||
| 280 | p.pushLexer( new MathLexer( fIn ) ); | 351 | p.pushLexer( new MathLexer( fIn ) ); |
diff --git a/src/unit/fstring.unit b/src/unit/fstring.unit index 00b6eed..c6d7414 100644 --- a/src/unit/fstring.unit +++ b/src/unit/fstring.unit | |||
| @@ -339,4 +339,13 @@ suite FString | |||
| 339 | a = "This is a test."; | 339 | a = "This is a test."; |
| 340 | unitTest( a.replace("i", "ooo") == "Thooos ooos a test." ); | 340 | unitTest( a.replace("i", "ooo") == "Thooos ooos a test." ); |
| 341 | } | 341 | } |
| 342 | |||
| 343 | test coreDerefBug1 | ||
| 344 | { | ||
| 345 | Bu::FString a, b; | ||
| 346 | a = "bob"; | ||
| 347 | a.setSize( 0 ); | ||
| 348 | b = a; | ||
| 349 | b.getStr(); | ||
| 350 | } | ||
| 342 | } | 351 | } |
diff --git a/src/unit/hash.unit b/src/unit/hash.unit index e3d7e42..124b074 100644 --- a/src/unit/hash.unit +++ b/src/unit/hash.unit | |||
| @@ -84,4 +84,17 @@ suite Hash | |||
| 84 | printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() ); | 84 | printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() ); |
| 85 | } */ | 85 | } */ |
| 86 | } | 86 | } |
| 87 | |||
| 88 | test copy | ||
| 89 | { | ||
| 90 | StrIntHash h; | ||
| 91 | h.insert("hello", 55 ); | ||
| 92 | h.insert("goodbye", -1812 ); | ||
| 93 | |||
| 94 | StrIntHash h2 = h; | ||
| 95 | unitTest( h2.isCoreShared( h ) ); | ||
| 96 | |||
| 97 | StrIntHash h3 = h.clone(); | ||
| 98 | unitTest( !h3.isCoreShared( h ) ); | ||
| 99 | } | ||
| 87 | } | 100 | } |
diff --git a/src/utfstring.cpp b/src/utfstring.cpp new file mode 100644 index 0000000..ae5efaf --- /dev/null +++ b/src/utfstring.cpp | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #include "bu/utfstring.h" | ||
| 2 | |||
| 3 | template class Bu::FBasicString<short>; | ||
| 4 | |||
| 5 | template<> uint32_t Bu::__calcHashCode<Bu::UtfString>( const Bu::UtfString &k ) | ||
| 6 | { | ||
| 7 | long j, sz = k.getSize()*2; | ||
| 8 | const char *s = (const char *)k.getStr(); | ||
| 9 | |||
| 10 | long nPos = 0; | ||
| 11 | for( j = 0; j < sz; j++, s++ ) | ||
| 12 | { | ||
| 13 | nPos = *s + (nPos << 6) + (nPos << 16) - nPos; | ||
| 14 | } | ||
| 15 | |||
| 16 | return nPos; | ||
| 17 | } | ||
| 18 | |||
| 19 | template<> bool Bu::__cmpHashKeys<Bu::UtfString>( | ||
| 20 | const Bu::UtfString &a, const Bu::UtfString &b ) | ||
| 21 | { | ||
| 22 | return a == b; | ||
| 23 | } | ||
| 24 | |||
| 25 | template<> void Bu::__tracer_format<Bu::UtfString>( const Bu::UtfString &v ) | ||
| 26 | { | ||
| 27 | printf("(%ld)\"%s\"", v.getSize(), (const char *)v.getStr() ); | ||
| 28 | } | ||
| 29 | |||
diff --git a/src/utfstring.h b/src/utfstring.h new file mode 100644 index 0000000..bbacb74 --- /dev/null +++ b/src/utfstring.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #ifndef BU_UTF_STRING_H | ||
| 2 | #define BU_UTF_STRING_H | ||
| 3 | |||
| 4 | #include "bu/fbasicstring.h" | ||
| 5 | |||
| 6 | namespace Bu | ||
| 7 | { | ||
| 8 | typedef FBasicString<short> UtfString; | ||
| 9 | |||
| 10 | template<typename T> | ||
| 11 | uint32_t __calcHashCode( const T &k ); | ||
| 12 | |||
| 13 | template<typename T> | ||
| 14 | bool __cmpHashKeys( const T &a, const T &b ); | ||
| 15 | |||
| 16 | template<> uint32_t __calcHashCode<UtfString>( const UtfString &k ); | ||
| 17 | template<> bool __cmpHashKeys<UtfString>( | ||
| 18 | const UtfString &a, const UtfString &b ); | ||
| 19 | |||
| 20 | template<typename t> void __tracer_format( const t &v ); | ||
| 21 | template<> void __tracer_format<UtfString>( const UtfString &v ); | ||
| 22 | } | ||
| 23 | |||
| 24 | #endif | ||
diff --git a/src/variant.h b/src/variant.h index 8e1203c..f659ad2 100644 --- a/src/variant.h +++ b/src/variant.h | |||
| @@ -17,6 +17,7 @@ namespace Bu | |||
| 17 | { | 17 | { |
| 18 | class Formatter; | 18 | class Formatter; |
| 19 | class Variant; | 19 | class Variant; |
| 20 | /** @cond DEVEL */ | ||
| 20 | template<class t> class VariantType; | 21 | template<class t> class VariantType; |
| 21 | 22 | ||
| 22 | class VariantTypeRoot | 23 | class VariantTypeRoot |
| @@ -92,7 +93,22 @@ namespace Bu | |||
| 92 | private: | 93 | private: |
| 93 | t data; | 94 | t data; |
| 94 | }; | 95 | }; |
| 95 | 96 | /** @endcond */ | |
| 97 | |||
| 98 | /** | ||
| 99 | * Store any data type and access it safely. Variant gives you a way to | ||
| 100 | * pass arbitrary data types around without having to worry about what | ||
| 101 | * type a variable is. It allows code to be easily extended and to manage | ||
| 102 | * data without having to know what type it is ahead of time. | ||
| 103 | * | ||
| 104 | * Because of the generic method that this class was implemented it may seem | ||
| 105 | * to have some drawbacks compared to other Variant classes you may have | ||
| 106 | * seen, however it is fairly easy to get it to do just about anything you | ||
| 107 | * may need. It is also very low overhead. On most compilers the class | ||
| 108 | * itself has only 3 words of overhead + the size of the variable you store | ||
| 109 | * in it. And, since many parts of it are templatized they can often be | ||
| 110 | * optimized quite a bit. | ||
| 111 | */ | ||
| 96 | class Variant | 112 | class Variant |
| 97 | { | 113 | { |
| 98 | public: | 114 | public: |
