diff options
author | Mike Buland <eichlan@xagasoft.com> | 2007-07-03 00:28:59 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2007-07-03 00:28:59 +0000 |
commit | ac517a2b7625e0aa0862679e961c6349f859ea3b (patch) | |
tree | e3e27a6b9bd5e2be6150088495c91fc91786ad9d /src | |
parent | f8d4301e9fa4f3709258505941e37fab2eadadc6 (diff) | |
parent | bd865cee5f89116c1f054cd0e5c275e97c2d0a9b (diff) | |
download | libbu++-ac517a2b7625e0aa0862679e961c6349f859ea3b.tar.gz libbu++-ac517a2b7625e0aa0862679e961c6349f859ea3b.tar.bz2 libbu++-ac517a2b7625e0aa0862679e961c6349f859ea3b.tar.xz libbu++-ac517a2b7625e0aa0862679e961c6349f859ea3b.zip |
The reorg is being put in trunk, I think it's ready. Now we just get to find
out how many applications won't work anymore :)
Diffstat (limited to '')
-rw-r--r-- | src/archival.cpp | 10 | ||||
-rw-r--r-- | src/archival.h | 38 | ||||
-rw-r--r-- | src/archive.cpp | 386 | ||||
-rw-r--r-- | src/archive.h | 212 | ||||
-rw-r--r-- | src/arraylist.cpp | 100 | ||||
-rw-r--r-- | src/arraylist.h | 80 | ||||
-rw-r--r-- | src/atom.cpp | 1 | ||||
-rw-r--r-- | src/atom.h | 107 | ||||
-rw-r--r-- | src/bzip2.cpp | 196 | ||||
-rw-r--r-- | src/bzip2.h | 37 | ||||
-rw-r--r-- | src/client.cpp | 206 | ||||
-rw-r--r-- | src/client.h | 63 | ||||
-rw-r--r-- | src/entities/bu-class | 48 | ||||
-rw-r--r-- | src/exceptionbase.cpp | 16 | ||||
-rw-r--r-- | src/exceptionbase.h | 127 | ||||
-rw-r--r-- | src/exceptions.cpp | 15 | ||||
-rw-r--r-- | src/exceptions.h | 43 | ||||
-rw-r--r-- | src/file.cpp | 158 | ||||
-rw-r--r-- | src/file.h | 78 | ||||
-rw-r--r-- | src/filter.cpp | 97 | ||||
-rw-r--r-- | src/filter.h | 65 | ||||
-rw-r--r-- | src/fstring.cpp | 11 | ||||
-rw-r--r-- | src/fstring.h | 1304 | ||||
-rw-r--r-- | src/hash.cpp | 34 | ||||
-rw-r--r-- | src/hash.h | 1488 | ||||
-rw-r--r-- | src/hashable.cpp | 1 | ||||
-rw-r--r-- | src/hashable.h | 12 | ||||
-rw-r--r-- | src/hashfunction.cpp | 10 | ||||
-rw-r--r-- | src/hashfunction.h | 48 | ||||
-rw-r--r-- | src/hashfunctioncasestring.cpp | 39 | ||||
-rw-r--r-- | src/hashfunctioncasestring.h | 28 | ||||
-rw-r--r-- | src/hashfunctionint.cpp | 20 | ||||
-rw-r--r-- | src/hashfunctionint.h | 26 | ||||
-rw-r--r-- | src/hashfunctionstring.cpp | 51 | ||||
-rw-r--r-- | src/hashfunctionstring.h | 27 | ||||
-rw-r--r-- | src/hashtable.cpp | 424 | ||||
-rw-r--r-- | src/hashtable.h | 308 | ||||
-rw-r--r-- | src/inprogress/xmldocument.cpp | 9 | ||||
-rw-r--r-- | src/inprogress/xmldocument.h | 22 | ||||
-rw-r--r-- | src/inprogress/xmlnode.cpp | 9 | ||||
-rw-r--r-- | src/inprogress/xmlnode.h | 22 | ||||
-rw-r--r-- | src/inprogress/xmlreader.cpp | 267 | ||||
-rw-r--r-- | src/inprogress/xmlreader.h | 121 | ||||
-rw-r--r-- | src/inprogress/xmlwriter.cpp | 9 | ||||
-rw-r--r-- | src/inprogress/xmlwriter.h | 22 | ||||
-rw-r--r-- | src/ito.cpp | 40 | ||||
-rw-r--r-- | src/ito.h | 98 | ||||
-rw-r--r-- | src/itoatom.h | 56 | ||||
-rw-r--r-- | src/itocondition.cpp | 42 | ||||
-rw-r--r-- | src/itocondition.h | 81 | ||||
-rw-r--r-- | src/itomutex.cpp | 27 | ||||
-rw-r--r-- | src/itomutex.h | 61 | ||||
-rw-r--r-- | src/itoqueue.h | 231 | ||||
-rw-r--r-- | src/linkmessage.cpp | 7 | ||||
-rw-r--r-- | src/linkmessage.h | 59 | ||||
-rw-r--r-- | src/list.cpp | 10 | ||||
-rw-r--r-- | src/list.h | 574 | ||||
-rw-r--r-- | src/logger.cpp | 131 | ||||
-rw-r--r-- | src/logger.h | 112 | ||||
-rw-r--r-- | src/main.dox | 14 | ||||
-rw-r--r-- | src/membuf.cpp | 120 | ||||
-rw-r--r-- | src/membuf.h | 53 | ||||
-rw-r--r-- | src/old/cgi.cpp (renamed from src/cgi.cpp) | 0 | ||||
-rw-r--r-- | src/old/cgi.h (renamed from src/cgi.h) | 0 | ||||
-rw-r--r-- | src/old/configmanagerbase.cpp (renamed from src/configmanagerbase.cpp) | 0 | ||||
-rw-r--r-- | src/old/configmanagerbase.h (renamed from src/configmanagerbase.h) | 0 | ||||
-rw-r--r-- | src/old/confpair.cpp (renamed from src/confpair.cpp) | 0 | ||||
-rw-r--r-- | src/old/confpair.h (renamed from src/confpair.h) | 0 | ||||
-rw-r--r-- | src/old/confpairbase.cpp (renamed from src/confpairbase.cpp) | 0 | ||||
-rw-r--r-- | src/old/confpairbase.h (renamed from src/confpairbase.h) | 0 | ||||
-rw-r--r-- | src/old/conftree.cpp (renamed from src/conftree.cpp) | 0 | ||||
-rw-r--r-- | src/old/conftree.h (renamed from src/conftree.h) | 0 | ||||
-rw-r--r-- | src/old/connection.cpp (renamed from src/connection.cpp) | 0 | ||||
-rw-r--r-- | src/old/connection.h (renamed from src/connection.h) | 0 | ||||
-rw-r--r-- | src/old/connectionmanager.cpp (renamed from src/connectionmanager.cpp) | 0 | ||||
-rw-r--r-- | src/old/connectionmanager.h (renamed from src/connectionmanager.h) | 0 | ||||
-rw-r--r-- | src/old/connectionmonitor.cpp (renamed from src/connectionmonitor.cpp) | 0 | ||||
-rw-r--r-- | src/old/connectionmonitor.h (renamed from src/connectionmonitor.h) | 0 | ||||
-rw-r--r-- | src/old/flexbuf.cpp (renamed from src/flexbuf.cpp) | 0 | ||||
-rw-r--r-- | src/old/flexbuf.h (renamed from src/flexbuf.h) | 0 | ||||
-rw-r--r-- | src/old/formula.cpp (renamed from src/formula.cpp) | 0 | ||||
-rw-r--r-- | src/old/formula.h (renamed from src/formula.h) | 0 | ||||
-rw-r--r-- | src/old/http.cpp (renamed from src/http.cpp) | 0 | ||||
-rw-r--r-- | src/old/http.h (renamed from src/http.h) | 0 | ||||
-rw-r--r-- | src/old/httpget.cpp (renamed from src/httpget.cpp) | 0 | ||||
-rw-r--r-- | src/old/httpget.h (renamed from src/httpget.h) | 0 | ||||
-rw-r--r-- | src/old/linkedlist.cpp (renamed from src/linkedlist.cpp) | 0 | ||||
-rw-r--r-- | src/old/linkedlist.h (renamed from src/linkedlist.h) | 0 | ||||
-rw-r--r-- | src/old/linkmessenger.cpp (renamed from src/linkmessenger.cpp) | 0 | ||||
-rw-r--r-- | src/old/linkmessenger.h (renamed from src/linkmessenger.h) | 0 | ||||
-rw-r--r-- | src/old/list.cpp | 10 | ||||
-rw-r--r-- | src/old/list.h | 101 | ||||
-rw-r--r-- | src/old/md5.cpp (renamed from src/md5.cpp) | 0 | ||||
-rw-r--r-- | src/old/md5.h (renamed from src/md5.h) | 0 | ||||
-rw-r--r-- | src/old/multilog.cpp (renamed from src/multilog.cpp) | 0 | ||||
-rw-r--r-- | src/old/multilog.h (renamed from src/multilog.h) | 0 | ||||
-rw-r--r-- | src/old/multilogchannel.cpp (renamed from src/multilogchannel.cpp) | 0 | ||||
-rw-r--r-- | src/old/multilogchannel.h (renamed from src/multilogchannel.h) | 0 | ||||
-rw-r--r-- | src/old/multilogtext.cpp (renamed from src/multilogtext.cpp) | 0 | ||||
-rw-r--r-- | src/old/multilogtext.h (renamed from src/multilogtext.h) | 0 | ||||
-rw-r--r-- | src/old/ordhash.cpp (renamed from src/ordhash.cpp) | 0 | ||||
-rw-r--r-- | src/old/ordhash.h (renamed from src/ordhash.h) | 0 | ||||
-rw-r--r-- | src/old/pqueue.cpp (renamed from src/pqueue.cpp) | 0 | ||||
-rw-r--r-- | src/old/pqueue.h (renamed from src/pqueue.h) | 0 | ||||
-rw-r--r-- | src/old/protocol.cpp | 20 | ||||
-rw-r--r-- | src/old/protocol.h | 62 | ||||
-rw-r--r-- | src/old/protocoltelnet.cpp (renamed from src/protocoltelnet.cpp) | 0 | ||||
-rw-r--r-- | src/old/protocoltelnet.h (renamed from src/protocoltelnet.h) | 0 | ||||
-rw-r--r-- | src/old/queue.cpp (renamed from src/queue.cpp) | 0 | ||||
-rw-r--r-- | src/old/queue.h (renamed from src/queue.h) | 0 | ||||
-rw-r--r-- | src/old/ringlist.cpp (renamed from src/ringlist.cpp) | 0 | ||||
-rw-r--r-- | src/old/ringlist.h (renamed from src/ringlist.h) | 0 | ||||
-rw-r--r-- | src/old/sbuffer.cpp (renamed from src/sbuffer.cpp) | 0 | ||||
-rw-r--r-- | src/old/sbuffer.h (renamed from src/sbuffer.h) | 0 | ||||
-rw-r--r-- | src/old/serializerbinary.cpp (renamed from src/serializerbinary.cpp) | 0 | ||||
-rw-r--r-- | src/old/serializerbinary.h (renamed from src/serializerbinary.h) | 0 | ||||
-rw-r--r-- | src/old/serializerbzip2.cpp (renamed from src/serializerbzip2.cpp) | 0 | ||||
-rw-r--r-- | src/old/serializerbzip2.h (renamed from src/serializerbzip2.h) | 0 | ||||
-rw-r--r-- | src/old/serializerconnection.cpp (renamed from src/serializerconnection.cpp) | 0 | ||||
-rw-r--r-- | src/old/serializerconnection.h (renamed from src/serializerconnection.h) | 0 | ||||
-rw-r--r-- | src/old/serializertext.cpp (renamed from src/serializertext.cpp) | 0 | ||||
-rw-r--r-- | src/old/serializertext.h (renamed from src/serializertext.h) | 0 | ||||
-rw-r--r-- | src/old/sha1.cpp (renamed from src/sha1.cpp) | 0 | ||||
-rw-r--r-- | src/old/sha1.h (renamed from src/sha1.h) | 0 | ||||
-rw-r--r-- | src/old/stack.cpp (renamed from src/stack.cpp) | 0 | ||||
-rw-r--r-- | src/old/stack.h (renamed from src/stack.h) | 0 | ||||
-rw-r--r-- | src/old/staticstring.cpp (renamed from src/staticstring.cpp) | 0 | ||||
-rw-r--r-- | src/old/staticstring.h (renamed from src/staticstring.h) | 0 | ||||
-rw-r--r-- | src/old/stringrep.cpp (renamed from src/stringrep.cpp) | 0 | ||||
-rw-r--r-- | src/old/stringrep.h (renamed from src/stringrep.h) | 0 | ||||
-rw-r--r-- | src/old/tests/clistress.cpp (renamed from src/tests/clistress.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/confpair.cpp (renamed from src/tests/confpair.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/connect.cpp (renamed from src/tests/connect.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/exception.cpp (renamed from src/tests/exception.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/formula.cpp (renamed from src/tests/formula.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/hash.cpp | 116 | ||||
-rw-r--r-- | src/old/tests/hashtest.cpp (renamed from src/tests/hashtest.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/hashtest2.cpp (renamed from src/tests/hashtest2.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/httpsrv/httpconnectionmonitor.cpp (renamed from src/tests/httpsrv/httpconnectionmonitor.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/httpsrv/httpconnectionmonitor.h (renamed from src/tests/httpsrv/httpconnectionmonitor.h) | 0 | ||||
-rw-r--r-- | src/old/tests/httpsrv/main.cpp (renamed from src/tests/httpsrv/main.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/log.cpp (renamed from src/tests/log.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/md5test.cpp (renamed from src/tests/md5test.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/ordhash.cpp (renamed from src/tests/ordhash.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/param.cpp (renamed from src/tests/param.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/param.h (renamed from src/tests/param.h) | 0 | ||||
-rw-r--r-- | src/old/tests/plugin/main.cpp (renamed from src/tests/plugin/main.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/plugin/plugin.cpp (renamed from src/tests/plugin/plugin.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/plugin/plugin.h (renamed from src/tests/plugin/plugin.h) | 0 | ||||
-rw-r--r-- | src/old/tests/qsort.cpp (renamed from src/tests/qsort.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/sbuffer.cpp (renamed from src/tests/sbuffer.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/serialize.cpp (renamed from src/tests/serialize.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/serializetext.cpp (renamed from src/tests/serializetext.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/sha1.cpp (renamed from src/tests/sha1.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/sptr.cpp (renamed from src/tests/sptr.cpp) | 30 | ||||
-rw-r--r-- | src/old/tests/srvstress.cpp (renamed from src/tests/srvstress.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/strhash.cpp (renamed from src/tests/strhash.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/teltest/main.cpp (renamed from src/tests/teltest/main.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/teltest/telnetmonitor.cpp (renamed from src/tests/teltest/telnetmonitor.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/teltest/telnetmonitor.h (renamed from src/tests/teltest/telnetmonitor.h) | 0 | ||||
-rw-r--r-- | src/old/tests/xmlreadtest.cpp (renamed from src/tests/xmlreadtest.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/xmlrepltest.cpp (renamed from src/tests/xmlrepltest.cpp) | 0 | ||||
-rw-r--r-- | src/old/tests/xmlwritetest.cpp (renamed from src/tests/xmlwritetest.cpp) | 0 | ||||
-rw-r--r-- | src/old/tokenstring.cpp (renamed from src/tokenstring.cpp) | 0 | ||||
-rw-r--r-- | src/old/tokenstring.h (renamed from src/tokenstring.h) | 0 | ||||
-rw-r--r-- | src/old/tqsort.h (renamed from src/tqsort.h) | 0 | ||||
-rw-r--r-- | src/old/unit/hashtable/hashtable.cpp (renamed from src/unit/hashtable/hashtable.cpp) | 0 | ||||
-rw-r--r-- | src/old/unit/xml/xml.cpp (renamed from src/unit/xml/xml.cpp) | 0 | ||||
-rw-r--r-- | src/old/xmldocument.cpp (renamed from src/xmldocument.cpp) | 20 | ||||
-rw-r--r-- | src/old/xmldocument.h (renamed from src/xmldocument.h) | 8 | ||||
-rw-r--r-- | src/old/xmlfilereader.cpp (renamed from src/xmlfilereader.cpp) | 0 | ||||
-rw-r--r-- | src/old/xmlfilereader.h (renamed from src/xmlfilereader.h) | 0 | ||||
-rw-r--r-- | src/old/xmlfilewriter.cpp (renamed from src/xmlfilewriter.cpp) | 0 | ||||
-rw-r--r-- | src/old/xmlfilewriter.h (renamed from src/xmlfilewriter.h) | 0 | ||||
-rw-r--r-- | src/old/xmlnode.cpp (renamed from src/xmlnode.cpp) | 106 | ||||
-rw-r--r-- | src/old/xmlnode.h (renamed from src/xmlnode.h) | 101 | ||||
-rw-r--r-- | src/old/xmlreader.cpp (renamed from src/xmlreader.cpp) | 170 | ||||
-rw-r--r-- | src/old/xmlreader.h (renamed from src/xmlreader.h) | 31 | ||||
-rw-r--r-- | src/old/xmlstringreader.cpp (renamed from src/xmlstringreader.cpp) | 0 | ||||
-rw-r--r-- | src/old/xmlstringreader.h (renamed from src/xmlstringreader.h) | 0 | ||||
-rw-r--r-- | src/old/xmlstringwriter.cpp (renamed from src/xmlstringwriter.cpp) | 0 | ||||
-rw-r--r-- | src/old/xmlstringwriter.h (renamed from src/xmlstringwriter.h) | 0 | ||||
-rw-r--r-- | src/old/xmlwriter.cpp (renamed from src/xmlwriter.cpp) | 62 | ||||
-rw-r--r-- | src/old/xmlwriter.h (renamed from src/xmlwriter.h) | 16 | ||||
-rw-r--r-- | src/paramproc.cpp | 98 | ||||
-rw-r--r-- | src/paramproc.h | 265 | ||||
-rw-r--r-- | src/plugger.h | 316 | ||||
-rw-r--r-- | src/programchain.cpp | 49 | ||||
-rw-r--r-- | src/programchain.h | 163 | ||||
-rw-r--r-- | src/programlink.cpp | 14 | ||||
-rw-r--r-- | src/programlink.h | 165 | ||||
-rw-r--r-- | src/protocol.cpp | 16 | ||||
-rw-r--r-- | src/protocol.h | 67 | ||||
-rw-r--r-- | src/ringbuffer.cpp | 2 | ||||
-rw-r--r-- | src/ringbuffer.h | 97 | ||||
-rw-r--r-- | src/serializable.cpp | 8 | ||||
-rw-r--r-- | src/serializable.h | 34 | ||||
-rw-r--r-- | src/serializer.cpp | 338 | ||||
-rw-r--r-- | src/serializer.h | 80 | ||||
-rw-r--r-- | src/server.cpp | 96 | ||||
-rw-r--r-- | src/server.h | 61 | ||||
-rw-r--r-- | src/serversocket.cpp | 158 | ||||
-rw-r--r-- | src/serversocket.h | 39 | ||||
-rw-r--r-- | src/sfile.cpp | 74 | ||||
-rw-r--r-- | src/sfile.h | 29 | ||||
-rw-r--r-- | src/singleton.h | 101 | ||||
-rw-r--r-- | src/socket.cpp | 294 | ||||
-rw-r--r-- | src/socket.h | 55 | ||||
-rw-r--r-- | src/sptr.cpp | 2 | ||||
-rw-r--r-- | src/sptr.h | 272 | ||||
-rw-r--r-- | src/stream.cpp | 4 | ||||
-rw-r--r-- | src/stream.h | 148 | ||||
-rw-r--r-- | src/tafnode.cpp | 165 | ||||
-rw-r--r-- | src/tafnode.h | 94 | ||||
-rw-r--r-- | src/tafreader.cpp | 155 | ||||
-rw-r--r-- | src/tafreader.h | 35 | ||||
-rw-r--r-- | src/tafwriter.cpp | 70 | ||||
-rw-r--r-- | src/tafwriter.h | 30 | ||||
-rw-r--r-- | src/tests/archive.cpp | 16 | ||||
-rw-r--r-- | src/tests/atom.cpp | 25 | ||||
-rw-r--r-- | src/tests/bzip2.cpp | 23 | ||||
-rw-r--r-- | src/tests/constsptr.cpp | 94 | ||||
-rw-r--r-- | src/tests/constsptr2.cpp | 30 | ||||
-rw-r--r-- | src/tests/fstring.cpp | 108 | ||||
-rw-r--r-- | src/tests/hash.cpp | 120 | ||||
-rw-r--r-- | src/tests/itoqueue1.cpp | 110 | ||||
-rw-r--r-- | src/tests/itoqueue2.cpp | 83 | ||||
-rw-r--r-- | src/tests/list.cpp | 53 | ||||
-rw-r--r-- | src/tests/logger.cpp | 28 | ||||
-rw-r--r-- | src/tests/ringbuffer.cpp | 29 | ||||
-rw-r--r-- | src/tests/taf.cpp | 24 | ||||
-rw-r--r-- | src/unit/entities/unit | 30 | ||||
-rw-r--r-- | src/unit/file.cpp | 111 | ||||
-rw-r--r-- | src/unit/fstring.cpp | 28 | ||||
-rw-r--r-- | src/unit/hash.cpp | 40 | ||||
-rw-r--r-- | src/unit/membuf.cpp | 37 | ||||
-rw-r--r-- | src/unit/taf.cpp | 48 | ||||
-rw-r--r-- | src/unitsuite.cpp | 67 | ||||
-rw-r--r-- | src/unitsuite.h | 96 |
239 files changed, 9329 insertions, 4429 deletions
diff --git a/src/archival.cpp b/src/archival.cpp new file mode 100644 index 0000000..79c28f1 --- /dev/null +++ b/src/archival.cpp | |||
@@ -0,0 +1,10 @@ | |||
1 | #include "archival.h" | ||
2 | |||
3 | Bu::Archival::Archival() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::Archival::~Archival() | ||
8 | { | ||
9 | } | ||
10 | |||
diff --git a/src/archival.h b/src/archival.h new file mode 100644 index 0000000..8be3308 --- /dev/null +++ b/src/archival.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef BU_ARCHIVAL_H | ||
2 | #define BU_ARCHIVAL_H | ||
3 | |||
4 | namespace Bu | ||
5 | { | ||
6 | /** | ||
7 | * The base class for any class you want to archive. Simply include this as | ||
8 | * a base class, implement the purely virtual archive function and you've | ||
9 | * got an easily archiveable class. | ||
10 | * | ||
11 | * Archival: "of or pertaining to archives or valuable records; contained | ||
12 | * in or comprising such archives or records." | ||
13 | */ | ||
14 | class Archival | ||
15 | { | ||
16 | public: | ||
17 | /** | ||
18 | * Does nothing, here for completeness. | ||
19 | */ | ||
20 | Archival(); | ||
21 | |||
22 | /** | ||
23 | * Here to ensure the deconstructor is virtual. | ||
24 | */ | ||
25 | virtual ~Archival(); | ||
26 | |||
27 | /** | ||
28 | * This is the main workhorse of the archive system, just override and | ||
29 | * you've got a archiveable class. A reference to the Archive | ||
30 | * used is passed in as your only parameter, query it to discover if | ||
31 | * you are loading or saving. | ||
32 | * @param ar A reference to the Archive object to use. | ||
33 | */ | ||
34 | virtual void archive( class Archive &ar )=0; | ||
35 | }; | ||
36 | } | ||
37 | |||
38 | #endif | ||
diff --git a/src/archive.cpp b/src/archive.cpp new file mode 100644 index 0000000..7208bae --- /dev/null +++ b/src/archive.cpp | |||
@@ -0,0 +1,386 @@ | |||
1 | #include "archive.h" | ||
2 | |||
3 | Bu::Archive::Archive( Stream &rStream, bool bLoading ) : | ||
4 | bLoading( bLoading ), | ||
5 | rStream( rStream ), | ||
6 | nNextID( 1 ) | ||
7 | { | ||
8 | } | ||
9 | |||
10 | Bu::Archive::~Archive() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | void Bu::Archive::write( const void *pData, int32_t nSize ) | ||
15 | { | ||
16 | if( nSize == 0 || pData == NULL ) | ||
17 | return; | ||
18 | |||
19 | rStream.write( (const char *)pData, nSize ); | ||
20 | } | ||
21 | |||
22 | void Bu::Archive::read( void *pData, int32_t nSize ) | ||
23 | { | ||
24 | if( nSize == 0 || pData == NULL ) | ||
25 | return; | ||
26 | |||
27 | rStream.read( (char *)pData, nSize ); | ||
28 | } | ||
29 | |||
30 | void Bu::Archive::close() | ||
31 | { | ||
32 | rStream.close(); | ||
33 | } | ||
34 | |||
35 | bool Bu::Archive::isLoading() | ||
36 | { | ||
37 | return bLoading; | ||
38 | } | ||
39 | Bu::Archive &Bu::Archive::operator<<(bool p) | ||
40 | { | ||
41 | write( &p, sizeof(p) ); | ||
42 | return *this; | ||
43 | } | ||
44 | Bu::Archive &Bu::Archive::operator<<(int8_t p) | ||
45 | { | ||
46 | write( &p, sizeof(p) ); | ||
47 | return *this; | ||
48 | } | ||
49 | Bu::Archive &Bu::Archive::operator<<(int16_t p) | ||
50 | { | ||
51 | write( &p, sizeof(p) ); | ||
52 | return *this; | ||
53 | } | ||
54 | Bu::Archive &Bu::Archive::operator<<(int32_t p) | ||
55 | { | ||
56 | write( &p, sizeof(p) ); | ||
57 | return *this; | ||
58 | } | ||
59 | Bu::Archive &Bu::Archive::operator<<(int64_t p) | ||
60 | { | ||
61 | write( &p, sizeof(p) ); | ||
62 | return *this; | ||
63 | } | ||
64 | Bu::Archive &Bu::Archive::operator<<(uint8_t p) | ||
65 | { | ||
66 | write( &p, sizeof(p) ); | ||
67 | return *this; | ||
68 | } | ||
69 | Bu::Archive &Bu::Archive::operator<<(uint16_t p) | ||
70 | { | ||
71 | write( &p, sizeof(p) ); | ||
72 | return *this; | ||
73 | } | ||
74 | Bu::Archive &Bu::Archive::operator<<(uint32_t p) | ||
75 | { | ||
76 | write( &p, sizeof(p) ); | ||
77 | return *this; | ||
78 | } | ||
79 | Bu::Archive &Bu::Archive::operator<<(uint64_t p) | ||
80 | { | ||
81 | write( &p, sizeof(p) ); | ||
82 | return *this; | ||
83 | } | ||
84 | Bu::Archive &Bu::Archive::operator<<(long p) | ||
85 | { | ||
86 | write( &p, sizeof(p) ); | ||
87 | return *this; | ||
88 | } | ||
89 | Bu::Archive &Bu::Archive::operator<<(float p) | ||
90 | { | ||
91 | write( &p, sizeof(p) ); | ||
92 | return *this; | ||
93 | } | ||
94 | Bu::Archive &Bu::Archive::operator<<(double p) | ||
95 | { | ||
96 | write( &p, sizeof(p) ); | ||
97 | return *this; | ||
98 | } | ||
99 | Bu::Archive &Bu::Archive::operator<<(long double p) | ||
100 | { | ||
101 | write( &p, sizeof(p) ); | ||
102 | return *this; | ||
103 | } | ||
104 | |||
105 | Bu::Archive &Bu::Archive::operator>>(bool &p) | ||
106 | { | ||
107 | read( &p, sizeof(p) ); | ||
108 | return *this; | ||
109 | } | ||
110 | Bu::Archive &Bu::Archive::operator>>(int8_t &p) | ||
111 | { | ||
112 | read( &p, sizeof(p) ); | ||
113 | return *this; | ||
114 | } | ||
115 | Bu::Archive &Bu::Archive::operator>>(int16_t &p) | ||
116 | { | ||
117 | read( &p, sizeof(p) ); | ||
118 | return *this; | ||
119 | } | ||
120 | Bu::Archive &Bu::Archive::operator>>(int32_t &p) | ||
121 | { | ||
122 | read( &p, sizeof(p) ); | ||
123 | return *this; | ||
124 | } | ||
125 | Bu::Archive &Bu::Archive::operator>>(int64_t &p) | ||
126 | { | ||
127 | read( &p, sizeof(p) ); | ||
128 | return *this; | ||
129 | } | ||
130 | Bu::Archive &Bu::Archive::operator>>(uint8_t &p) | ||
131 | { | ||
132 | read( &p, sizeof(p) ); | ||
133 | return *this; | ||
134 | } | ||
135 | Bu::Archive &Bu::Archive::operator>>(uint16_t &p) | ||
136 | { | ||
137 | read( &p, sizeof(p) ); | ||
138 | return *this; | ||
139 | } | ||
140 | Bu::Archive &Bu::Archive::operator>>(uint32_t &p) | ||
141 | { | ||
142 | read( &p, sizeof(p) ); | ||
143 | return *this; | ||
144 | } | ||
145 | Bu::Archive &Bu::Archive::operator>>(uint64_t &p) | ||
146 | { | ||
147 | read( &p, sizeof(p) ); | ||
148 | return *this; | ||
149 | } | ||
150 | Bu::Archive &Bu::Archive::operator>>(long &p) | ||
151 | { | ||
152 | read( &p, sizeof(p) ); | ||
153 | return *this; | ||
154 | } | ||
155 | Bu::Archive &Bu::Archive::operator>>(float &p) | ||
156 | { | ||
157 | read( &p, sizeof(p) ); | ||
158 | return *this; | ||
159 | } | ||
160 | Bu::Archive &Bu::Archive::operator>>(double &p) | ||
161 | { | ||
162 | read( &p, sizeof(p) ); | ||
163 | return *this; | ||
164 | } | ||
165 | Bu::Archive &Bu::Archive::operator>>(long double &p) | ||
166 | { | ||
167 | read( &p, sizeof(p) ); | ||
168 | return *this; | ||
169 | } | ||
170 | |||
171 | Bu::Archive &Bu::Archive::operator&&(bool &p) | ||
172 | { | ||
173 | if (bLoading) | ||
174 | { | ||
175 | return *this >> p; | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | return *this << p; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | Bu::Archive &Bu::Archive::operator&&(int8_t &p) | ||
184 | { | ||
185 | if (bLoading) | ||
186 | { | ||
187 | return *this >> p; | ||
188 | } | ||
189 | else | ||
190 | { | ||
191 | return *this << p; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | Bu::Archive &Bu::Archive::operator&&(int16_t &p) | ||
196 | { | ||
197 | if (bLoading) | ||
198 | { | ||
199 | return *this >> p; | ||
200 | } | ||
201 | else | ||
202 | { | ||
203 | return *this << p; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | Bu::Archive &Bu::Archive::operator&&(int32_t &p) | ||
208 | { | ||
209 | if (bLoading) | ||
210 | { | ||
211 | return *this >> p; | ||
212 | } | ||
213 | else | ||
214 | { | ||
215 | return *this << p; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | Bu::Archive &Bu::Archive::operator&&(int64_t &p) | ||
220 | { | ||
221 | if (bLoading) | ||
222 | { | ||
223 | return *this >> p; | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | return *this << p; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | Bu::Archive &Bu::Archive::operator&&(uint8_t &p) | ||
232 | { | ||
233 | if (bLoading) | ||
234 | { | ||
235 | return *this >> p; | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | return *this << p; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | Bu::Archive &Bu::Archive::operator&&(uint16_t &p) | ||
244 | { | ||
245 | if (bLoading) | ||
246 | { | ||
247 | return *this >> p; | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | return *this << p; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | Bu::Archive &Bu::Archive::operator&&(uint32_t &p) | ||
256 | { | ||
257 | if (bLoading) | ||
258 | { | ||
259 | return *this >> p; | ||
260 | } | ||
261 | else | ||
262 | { | ||
263 | return *this << p; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | Bu::Archive &Bu::Archive::operator&&(uint64_t &p) | ||
268 | { | ||
269 | if (bLoading) | ||
270 | { | ||
271 | return *this >> p; | ||
272 | } | ||
273 | else | ||
274 | { | ||
275 | return *this << p; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | Bu::Archive &Bu::Archive::operator&&(float &p) | ||
280 | { | ||
281 | if (bLoading) | ||
282 | { | ||
283 | return *this >> p; | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | return *this << p; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | Bu::Archive &Bu::Archive::operator&&(double &p) | ||
292 | { | ||
293 | if (bLoading) | ||
294 | { | ||
295 | return *this >> p; | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | return *this << p; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | Bu::Archive &Bu::Archive::operator&&(long double &p) | ||
304 | { | ||
305 | if (bLoading) | ||
306 | { | ||
307 | return *this >> p; | ||
308 | } | ||
309 | else | ||
310 | { | ||
311 | return *this << p; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | |||
316 | Bu::Archive &Bu::operator<<(Bu::Archive &s, Bu::Archival &p) | ||
317 | { | ||
318 | p.archive( s ); | ||
319 | return s; | ||
320 | } | ||
321 | |||
322 | Bu::Archive &Bu::operator>>(Bu::Archive &s, Bu::Archival &p) | ||
323 | { | ||
324 | p.archive( s ); | ||
325 | return s; | ||
326 | } | ||
327 | |||
328 | Bu::Archive &Bu::operator<<( Bu::Archive &ar, std::string &s ) | ||
329 | { | ||
330 | ar << (uint32_t)s.length(); | ||
331 | ar.write( s.c_str(), s.length() ); | ||
332 | |||
333 | return ar; | ||
334 | } | ||
335 | |||
336 | Bu::Archive &Bu::operator>>( Bu::Archive &ar, std::string &s ) | ||
337 | { | ||
338 | uint32_t l; | ||
339 | ar >> l; | ||
340 | char *tmp = new char[l+1]; | ||
341 | tmp[l] = '\0'; | ||
342 | ar.read( tmp, l ); | ||
343 | s = tmp; | ||
344 | delete[] tmp; | ||
345 | |||
346 | return ar; | ||
347 | } | ||
348 | |||
349 | uint32_t Bu::Archive::getID( const void *ptr ) | ||
350 | { | ||
351 | if( hPtrID.has( (int)ptr ) ) | ||
352 | return hPtrID.get( (int)ptr ); | ||
353 | hPtrID.insert( (int)ptr, nNextID ); | ||
354 | return nNextID++; | ||
355 | } | ||
356 | |||
357 | void Bu::Archive::assocPtrID( void **ptr, uint32_t id ) | ||
358 | { | ||
359 | if( hPtrID.has( id ) ) | ||
360 | { | ||
361 | *ptr = (void *)hPtrID.get( id ); | ||
362 | return; | ||
363 | } | ||
364 | |||
365 | if( !hPtrDest.has( id ) ) | ||
366 | hPtrDest.insert( id, List<void **>() ); | ||
367 | |||
368 | hPtrDest[id].value().append( ptr ); | ||
369 | } | ||
370 | |||
371 | void Bu::Archive::readID( const void *ptr, uint32_t id ) | ||
372 | { | ||
373 | hPtrID.insert( id, (int)ptr ); | ||
374 | |||
375 | if( hPtrDest.has( id ) ) | ||
376 | { | ||
377 | Bu::List<void **> &l = hPtrDest.get( id ); | ||
378 | for( Bu::List<void **>::iterator i = l.begin(); i != l.end(); i++ ) | ||
379 | { | ||
380 | *(*i) = (void *)ptr; | ||
381 | } | ||
382 | |||
383 | hPtrDest.erase( id ); | ||
384 | } | ||
385 | } | ||
386 | |||
diff --git a/src/archive.h b/src/archive.h new file mode 100644 index 0000000..a2d4c8f --- /dev/null +++ b/src/archive.h | |||
@@ -0,0 +1,212 @@ | |||
1 | #ifndef BU_ARCHIVE_H | ||
2 | #define BU_ARCHIVE_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include <string> | ||
6 | #include "bu/archival.h" | ||
7 | #include "bu/stream.h" | ||
8 | #include <list> | ||
9 | #include "bu/hash.h" | ||
10 | #include "bu/list.h" | ||
11 | |||
12 | namespace Bu | ||
13 | { | ||
14 | /** | ||
15 | * Provides a framework for serialization of objects and primitives. The | ||
16 | * archive will handle any basic primitive, a few special types, like char * | ||
17 | * strings, as well as STL classes and anything that inherits from the | ||
18 | * Archival class. Each Archive operates on a Stream, so you can send the | ||
19 | * data using an Archive almost anywhere. | ||
20 | * | ||
21 | * In order to use an Archive to store something to a file, try something | ||
22 | * like: | ||
23 | *@code | ||
24 | * File sOut("output", "wb"); // This is a stream subclass | ||
25 | * Archive ar( sOut, Archive::save ); | ||
26 | * ar << myClass; | ||
27 | @endcode | ||
28 | * In this example myClass is any class that inherits from Archival. When | ||
29 | * the storage operator is called, the Archival::archive() function in the | ||
30 | * myClass object is called with a reference to the Archive. This can be | ||
31 | * handled in one of two ways: | ||
32 | *@code | ||
33 | * void MyClass::archive( Archive &ar ) | ||
34 | * { | ||
35 | * ar && sName && nAge && sJob; | ||
36 | * } | ||
37 | @endcode | ||
38 | * Here we don't worry about weather we're loading or saving by using the | ||
39 | * smart && operator. This allows us to write very consistent, very simple | ||
40 | * archive functions that really do a lot of work. If we wanted to do | ||
41 | * something different in the case of loading or saving we would do: | ||
42 | *@code | ||
43 | * void MyClass::archive( Archive &ar ) | ||
44 | * { | ||
45 | * if( ar.isLoading() ) | ||
46 | * { | ||
47 | * ar >> sName >> nAge >> sJob; | ||
48 | * } else | ||
49 | * { | ||
50 | * ar << sName << nAge << sJob; | ||
51 | * } | ||
52 | * } | ||
53 | @endcode | ||
54 | * Archive currently does not provide facility to make fully portable | ||
55 | * archives. For example, it will not convert between endianness for you, | ||
56 | * nor will it take into account differences between primitive sizes on | ||
57 | * different platforms. This, at the moment, is up to the user to ensure. | ||
58 | * One way of dealing with the latter problem is to make sure and use | ||
59 | * explicit primitive types from the stdint.h header, i.e. int32_t. | ||
60 | */ | ||
61 | class Archive | ||
62 | { | ||
63 | private: | ||
64 | bool bLoading; | ||
65 | public: | ||
66 | bool isLoading(); | ||
67 | |||
68 | enum | ||
69 | { | ||
70 | load = true, | ||
71 | save = false | ||
72 | }; | ||
73 | |||
74 | Archive( Stream &rStream, bool bLoading ); | ||
75 | virtual ~Archive(); | ||
76 | virtual void close(); | ||
77 | |||
78 | virtual void write(const void *, int32_t); | ||
79 | virtual void read(void *, int32_t); | ||
80 | |||
81 | virtual Archive &operator<<(bool); | ||
82 | virtual Archive &operator<<(int8_t); | ||
83 | virtual Archive &operator<<(int16_t); | ||
84 | virtual Archive &operator<<(int32_t); | ||
85 | virtual Archive &operator<<(int64_t); | ||
86 | virtual Archive &operator<<(uint8_t); | ||
87 | virtual Archive &operator<<(uint16_t); | ||
88 | virtual Archive &operator<<(uint32_t); | ||
89 | virtual Archive &operator<<(uint64_t); | ||
90 | virtual Archive &operator<<(long); | ||
91 | virtual Archive &operator<<(float); | ||
92 | virtual Archive &operator<<(double); | ||
93 | virtual Archive &operator<<(long double); | ||
94 | |||
95 | virtual Archive &operator>>(bool &); | ||
96 | virtual Archive &operator>>(int8_t &); | ||
97 | virtual Archive &operator>>(int16_t &); | ||
98 | virtual Archive &operator>>(int32_t &); | ||
99 | virtual Archive &operator>>(int64_t &); | ||
100 | virtual Archive &operator>>(uint8_t &); | ||
101 | virtual Archive &operator>>(uint16_t &); | ||
102 | virtual Archive &operator>>(uint32_t &); | ||
103 | virtual Archive &operator>>(uint64_t &); | ||
104 | virtual Archive &operator>>(long &); | ||
105 | virtual Archive &operator>>(float &); | ||
106 | virtual Archive &operator>>(double &); | ||
107 | virtual Archive &operator>>(long double &); | ||
108 | |||
109 | virtual Archive &operator&&(bool &); | ||
110 | virtual Archive &operator&&(int8_t &); | ||
111 | virtual Archive &operator&&(int16_t &); | ||
112 | virtual Archive &operator&&(int32_t &); | ||
113 | virtual Archive &operator&&(int64_t &); | ||
114 | virtual Archive &operator&&(uint8_t &); | ||
115 | virtual Archive &operator&&(uint16_t &); | ||
116 | virtual Archive &operator&&(uint32_t &); | ||
117 | virtual Archive &operator&&(uint64_t &); | ||
118 | virtual Archive &operator&&(float &); | ||
119 | virtual Archive &operator&&(double &); | ||
120 | virtual Archive &operator&&(long double &); | ||
121 | |||
122 | uint32_t getID( const void *ptr ); | ||
123 | void assocPtrID( void **ptr, uint32_t id ); | ||
124 | void readID( const void *ptr, uint32_t id ); | ||
125 | |||
126 | private: | ||
127 | Stream &rStream; | ||
128 | uint32_t nNextID; | ||
129 | Hash<uint32_t,uint32_t> hPtrID; | ||
130 | Hash<uint32_t,List<void **> > hPtrDest; | ||
131 | }; | ||
132 | |||
133 | Archive &operator<<(Archive &, class Bu::Archival &); | ||
134 | Archive &operator>>(Archive &, class Bu::Archival &); | ||
135 | //Archive &operator&&(Archive &s, class Bu::Archival &p); | ||
136 | |||
137 | Archive &operator<<(Archive &, std::string &); | ||
138 | Archive &operator>>(Archive &, std::string &); | ||
139 | //Archive &operator&&(Archive &, std::string &); | ||
140 | |||
141 | template<typename T> Archive &operator&&( Archive &ar, T &dat ) | ||
142 | { | ||
143 | if( ar.isLoading() ) | ||
144 | { | ||
145 | return ar >> dat; | ||
146 | } | ||
147 | else | ||
148 | { | ||
149 | return ar << dat; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | template<typename T> Archive &operator<<( Archive &ar, std::list<T> &l ) | ||
154 | { | ||
155 | typename std::list<T>::size_type num = l.size(); | ||
156 | ar << num; | ||
157 | for( typename std::list<T>::const_iterator i = l.begin(); i != l.end(); | ||
158 | i++ ) | ||
159 | { | ||
160 | ar << *i; | ||
161 | } | ||
162 | |||
163 | return ar; | ||
164 | } | ||
165 | |||
166 | template<typename T> Archive &operator>>( Archive &ar, std::list<T> &l ) | ||
167 | { | ||
168 | typename std::list<T>::size_type num; | ||
169 | ar >> num; | ||
170 | |||
171 | l.resize( num ); | ||
172 | for( typename std::list<T>::const_iterator i = l.begin(); | ||
173 | i != l.end(); i++ ) | ||
174 | { | ||
175 | ar >> *i; | ||
176 | } | ||
177 | |||
178 | return ar; | ||
179 | } | ||
180 | |||
181 | template<typename key, typename value> | ||
182 | Archive &operator<<( Archive &ar, Hash<key,value> &h ) | ||
183 | { | ||
184 | ar << h.size(); | ||
185 | for( typename Hash<key,value>::iterator i = h.begin(); i != h.end(); i++ ) | ||
186 | { | ||
187 | //std::pair<key,value> p = *i; | ||
188 | ar << (i.getKey()) << (i.getValue()); | ||
189 | } | ||
190 | |||
191 | return ar; | ||
192 | } | ||
193 | |||
194 | template<typename key, typename value> | ||
195 | Archive &operator>>( Archive &ar, Hash<key,value> &h ) | ||
196 | { | ||
197 | h.clear(); | ||
198 | uint32_t nSize; | ||
199 | ar >> nSize; | ||
200 | |||
201 | for( uint32_t j = 0; j < nSize; j++ ) | ||
202 | { | ||
203 | key k; value v; | ||
204 | ar >> k >> v; | ||
205 | h.insert( k, v ); | ||
206 | } | ||
207 | |||
208 | return ar; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | #endif | ||
diff --git a/src/arraylist.cpp b/src/arraylist.cpp deleted file mode 100644 index ef21426..0000000 --- a/src/arraylist.cpp +++ /dev/null | |||
@@ -1,100 +0,0 @@ | |||
1 | #include "arraylist.h" | ||
2 | #include <stdlib.h> | ||
3 | #include <string.h> | ||
4 | |||
5 | ArrayList::ArrayList( int initSize, int growByFactor ) | ||
6 | { | ||
7 | apData = new void *[initSize]; | ||
8 | nSize = 0; | ||
9 | nCapacity = initSize; | ||
10 | nGrowByFactor = growByFactor; | ||
11 | } | ||
12 | |||
13 | ArrayList::~ArrayList( ) | ||
14 | { | ||
15 | delete[] apData; | ||
16 | } | ||
17 | |||
18 | void *ArrayList::getAt( int index ) | ||
19 | { | ||
20 | if( index < 0 || index > nSize ) | ||
21 | return NULL; | ||
22 | |||
23 | return apData[index]; | ||
24 | } | ||
25 | |||
26 | void ArrayList::append( void *data ) | ||
27 | { | ||
28 | insertBefore( data, nSize ); | ||
29 | } | ||
30 | |||
31 | void ArrayList::insertBefore( void *data, int pos ) | ||
32 | { | ||
33 | if( pos < 0 || pos > nSize ) | ||
34 | return; | ||
35 | |||
36 | checkResize(); | ||
37 | memmove( &apData[pos+1], &apData[pos], (nSize-pos)*sizeof(void*) ); | ||
38 | apData[pos] = data; | ||
39 | nSize++; | ||
40 | } | ||
41 | |||
42 | int ArrayList::getSize( ) | ||
43 | { | ||
44 | return nSize; | ||
45 | } | ||
46 | |||
47 | bool ArrayList::isEmpty( ) | ||
48 | { | ||
49 | return nSize==0; | ||
50 | } | ||
51 | |||
52 | void ArrayList::deleteAt( int index ) | ||
53 | { | ||
54 | if( index < 0 || index >= nSize ) | ||
55 | return; | ||
56 | |||
57 | memmove( &apData[index], &apData[index+1], (nSize-index-1)*sizeof(void *) ); | ||
58 | nSize--; | ||
59 | } | ||
60 | |||
61 | void ArrayList::empty() | ||
62 | { | ||
63 | // Probably the easiest as far as things go. | ||
64 | nSize = 0; | ||
65 | } | ||
66 | |||
67 | void ArrayList::resizeTo( int newSize ) | ||
68 | { | ||
69 | void **apNew = new void *[newSize]; | ||
70 | memmove( apNew, apData, nSize*sizeof(void *) ); | ||
71 | nCapacity = newSize; | ||
72 | delete[] apData; | ||
73 | apData = apNew; | ||
74 | } | ||
75 | |||
76 | void ArrayList::checkResize() | ||
77 | { | ||
78 | if( nSize >= nCapacity ) | ||
79 | { | ||
80 | resizeTo( nCapacity + nGrowByFactor ); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | void ArrayList::setSize( int newSize ) | ||
85 | { | ||
86 | if( newSize < 0 ) | ||
87 | return; | ||
88 | |||
89 | nSize = newSize; | ||
90 | checkResize(); | ||
91 | } | ||
92 | |||
93 | void ArrayList::setAt( int index, void *data ) | ||
94 | { | ||
95 | if( index < 0 || index >= nSize ) | ||
96 | return; | ||
97 | |||
98 | apData[index] = data; | ||
99 | } | ||
100 | |||
diff --git a/src/arraylist.h b/src/arraylist.h deleted file mode 100644 index 0fda34a..0000000 --- a/src/arraylist.h +++ /dev/null | |||
@@ -1,80 +0,0 @@ | |||
1 | /** \file arraylist.h | ||
2 | * Describes the ArrayList class. | ||
3 | *@author Mike Buland | ||
4 | */ | ||
5 | #ifndef ARRAY_LIST_H | ||
6 | #define ARRAY_LIST_H | ||
7 | |||
8 | #include "list.h" | ||
9 | |||
10 | /** A simple list which uses an array. This is a great choice if you won't do | ||
11 | * a lot of adding and deleting and need a fast random access list. Otherwise | ||
12 | * use the LinkedList. | ||
13 | *@author Mike Buland | ||
14 | */ | ||
15 | class ArrayList : public List | ||
16 | { | ||
17 | public: | ||
18 | /** Creates an arraylist with some pre-defined specs spelled out. | ||
19 | *@param initSize the inital number of elements to allocate. | ||
20 | *@param growByFactor How much to increase the size of the array by | ||
21 | * each time we run out of room. | ||
22 | */ | ||
23 | ArrayList( int initSize=100, int growByFactor=10 ); | ||
24 | /** | ||
25 | * Destroy the ArrayList | ||
26 | */ | ||
27 | virtual ~ArrayList(); | ||
28 | |||
29 | void *getAt( int nIndex ); | ||
30 | void append( void *pData ); | ||
31 | void insertBefore( void *pData, int nPos = 0 ); | ||
32 | int getSize( ); | ||
33 | bool isEmpty( ); | ||
34 | void deleteAt( int nIndex ); | ||
35 | void empty(); | ||
36 | void setSize( int nNewSize ); | ||
37 | void setAt( int nIndex, void *pData ); | ||
38 | |||
39 | private: | ||
40 | /** | ||
41 | * Checks to see if the system needs to be resized, if it does, this will | ||
42 | * automatically resize based on your parameters. | ||
43 | */ | ||
44 | void checkResize(); | ||
45 | |||
46 | /** | ||
47 | * Resize the system to a specified size. If it is larger, then all data | ||
48 | * will be retained, if smaller the elements at the end will be cut off. | ||
49 | *@param newSize The number of elements to include after resizing. | ||
50 | */ | ||
51 | void resizeTo( int newSize ); | ||
52 | |||
53 | /** | ||
54 | * Actual master array of pointers. This is done to follow the List specs. | ||
55 | * All data transactions are performed with pointers or compatable | ||
56 | * primitive data-types. | ||
57 | */ | ||
58 | void **apData; | ||
59 | |||
60 | /** | ||
61 | * The number of filled in elements in the array. This is the practical | ||
62 | * real size of the ArrayList for all userspace applications. | ||
63 | */ | ||
64 | int nSize; | ||
65 | |||
66 | /** | ||
67 | * The number of elements allocated in memory. Not all of these have to be | ||
68 | * filled in, and it is usually larger than nSize so that adding and | ||
69 | * deleting elements is fast and easy. | ||
70 | */ | ||
71 | int nCapacity; | ||
72 | |||
73 | /** | ||
74 | * The amount to grow by whenever the array needs resizing. | ||
75 | */ | ||
76 | int nGrowByFactor; | ||
77 | }; | ||
78 | |||
79 | #endif | ||
80 | |||
diff --git a/src/atom.cpp b/src/atom.cpp new file mode 100644 index 0000000..f966bfc --- /dev/null +++ b/src/atom.cpp | |||
@@ -0,0 +1 @@ | |||
#include "bu/atom.h" | |||
diff --git a/src/atom.h b/src/atom.h new file mode 100644 index 0000000..fad47eb --- /dev/null +++ b/src/atom.h | |||
@@ -0,0 +1,107 @@ | |||
1 | #ifndef BU_ATOM_H | ||
2 | #define BU_ATOM_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include <memory> | ||
6 | #include "bu/exceptions.h" | ||
7 | |||
8 | namespace Bu | ||
9 | { | ||
10 | /** | ||
11 | * | ||
12 | */ | ||
13 | template <typename t, typename talloc=std::allocator<t> > | ||
14 | class Atom | ||
15 | { | ||
16 | private: | ||
17 | typedef struct Atom<t, talloc> MyType; | ||
18 | |||
19 | public: | ||
20 | Atom() : | ||
21 | pData( NULL ) | ||
22 | { | ||
23 | } | ||
24 | |||
25 | virtual ~Atom() | ||
26 | { | ||
27 | clear(); | ||
28 | } | ||
29 | |||
30 | bool has() const | ||
31 | { | ||
32 | return (pData != NULL); | ||
33 | } | ||
34 | |||
35 | void set( const t &val ) | ||
36 | { | ||
37 | clear(); | ||
38 | pData = ta.allocate( 1 ); | ||
39 | ta.construct( pData, val ); | ||
40 | } | ||
41 | |||
42 | t &get() | ||
43 | { | ||
44 | if( !pData ) | ||
45 | throw Bu::ExceptionBase("Not set"); | ||
46 | return *pData; | ||
47 | } | ||
48 | |||
49 | const t &get() const | ||
50 | { | ||
51 | if( !pData ) | ||
52 | throw Bu::ExceptionBase("Not set"); | ||
53 | return *pData; | ||
54 | } | ||
55 | |||
56 | void clear() | ||
57 | { | ||
58 | if( pData ) | ||
59 | { | ||
60 | ta.destroy( pData ); | ||
61 | ta.deallocate( pData, 1 ); | ||
62 | pData = NULL; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | operator const t &() const | ||
67 | { | ||
68 | if( !pData ) | ||
69 | throw Bu::ExceptionBase("Not set"); | ||
70 | return *pData; | ||
71 | } | ||
72 | |||
73 | operator t &() | ||
74 | { | ||
75 | if( !pData ) | ||
76 | throw Bu::ExceptionBase("Not set"); | ||
77 | return *pData; | ||
78 | } | ||
79 | |||
80 | MyType &operator =( const t &oth ) | ||
81 | { | ||
82 | set( oth ); | ||
83 | |||
84 | return *this; | ||
85 | } | ||
86 | |||
87 | t *operator ->() | ||
88 | { | ||
89 | if( !pData ) | ||
90 | throw Bu::ExceptionBase("Not set"); | ||
91 | return pData; | ||
92 | } | ||
93 | |||
94 | t &operator *() | ||
95 | { | ||
96 | if( !pData ) | ||
97 | throw Bu::ExceptionBase("Not set"); | ||
98 | return *pData; | ||
99 | } | ||
100 | |||
101 | private: | ||
102 | t *pData; | ||
103 | talloc ta; | ||
104 | }; | ||
105 | } | ||
106 | |||
107 | #endif | ||
diff --git a/src/bzip2.cpp b/src/bzip2.cpp new file mode 100644 index 0000000..fbe5712 --- /dev/null +++ b/src/bzip2.cpp | |||
@@ -0,0 +1,196 @@ | |||
1 | #include "bu/bzip2.h" | ||
2 | #include "bu/exceptions.h" | ||
3 | |||
4 | using namespace Bu; | ||
5 | |||
6 | Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) : | ||
7 | Bu::Filter( rNext ), | ||
8 | nCompression( nCompression ) | ||
9 | { | ||
10 | start(); | ||
11 | } | ||
12 | |||
13 | Bu::BZip2::~BZip2() | ||
14 | { | ||
15 | stop(); | ||
16 | } | ||
17 | |||
18 | void Bu::BZip2::start() | ||
19 | { | ||
20 | bzState.state = NULL; | ||
21 | bzState.bzalloc = NULL; | ||
22 | bzState.bzfree = NULL; | ||
23 | bzState.opaque = NULL; | ||
24 | |||
25 | nBufSize = 50000; | ||
26 | pBuf = new char[nBufSize]; | ||
27 | } | ||
28 | |||
29 | size_t Bu::BZip2::stop() | ||
30 | { | ||
31 | if( bzState.state ) | ||
32 | { | ||
33 | if( bReading ) | ||
34 | { | ||
35 | BZ2_bzDecompressEnd( &bzState ); | ||
36 | delete[] pBuf; | ||
37 | pBuf = NULL; | ||
38 | return 0; | ||
39 | } | ||
40 | else | ||
41 | { | ||
42 | size_t sTotal = 0; | ||
43 | for(;;) | ||
44 | { | ||
45 | bzState.next_in = NULL; | ||
46 | bzState.avail_in = 0; | ||
47 | bzState.avail_out = nBufSize; | ||
48 | bzState.next_out = pBuf; | ||
49 | int res = BZ2_bzCompress( &bzState, BZ_FINISH ); | ||
50 | if( bzState.avail_out < nBufSize ) | ||
51 | { | ||
52 | sTotal += rNext.write( pBuf, nBufSize-bzState.avail_out ); | ||
53 | } | ||
54 | if( res == BZ_STREAM_END ) | ||
55 | break; | ||
56 | } | ||
57 | BZ2_bzCompressEnd( &bzState ); | ||
58 | delete[] pBuf; | ||
59 | pBuf = NULL; | ||
60 | return sTotal; | ||
61 | } | ||
62 | } | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | void Bu::BZip2::bzError( int code ) | ||
67 | { | ||
68 | switch( code ) | ||
69 | { | ||
70 | case BZ_OK: | ||
71 | case BZ_RUN_OK: | ||
72 | case BZ_FLUSH_OK: | ||
73 | case BZ_FINISH_OK: | ||
74 | return; | ||
75 | |||
76 | case BZ_CONFIG_ERROR: | ||
77 | throw ExceptionBase("BZip2: Library configured improperly, reinstall."); | ||
78 | |||
79 | case BZ_SEQUENCE_ERROR: | ||
80 | throw ExceptionBase("BZip2: Functions were called in an invalid sequence."); | ||
81 | |||
82 | case BZ_PARAM_ERROR: | ||
83 | throw ExceptionBase("BZip2: Invalid parameter was passed into a function."); | ||
84 | |||
85 | case BZ_MEM_ERROR: | ||
86 | throw ExceptionBase("BZip2: Couldn't allocate sufficient memory."); | ||
87 | |||
88 | case BZ_DATA_ERROR: | ||
89 | throw ExceptionBase("BZip2: Data was corrupted before decompression."); | ||
90 | |||
91 | case BZ_DATA_ERROR_MAGIC: | ||
92 | throw ExceptionBase("BZip2: Stream does not appear to be bzip2 data."); | ||
93 | |||
94 | case BZ_IO_ERROR: | ||
95 | throw ExceptionBase("BZip2: File couldn't be read from / written to."); | ||
96 | |||
97 | case BZ_UNEXPECTED_EOF: | ||
98 | throw ExceptionBase("BZip2: End of file encountered before end of stream."); | ||
99 | |||
100 | case BZ_OUTBUFF_FULL: | ||
101 | throw ExceptionBase("BZip2: Buffer not large enough to accomidate data."); | ||
102 | |||
103 | default: | ||
104 | throw ExceptionBase("BZip2: Unknown error encountered."); | ||
105 | |||
106 | } | ||
107 | } | ||
108 | |||
109 | size_t Bu::BZip2::read( void *pData, size_t nBytes ) | ||
110 | { | ||
111 | if( !bzState.state ) | ||
112 | { | ||
113 | bReading = true; | ||
114 | BZ2_bzDecompressInit( &bzState, 0, 0 ); | ||
115 | bzState.next_in = pBuf; | ||
116 | bzState.avail_in = 0; | ||
117 | } | ||
118 | if( bReading == false ) | ||
119 | throw ExceptionBase("This bzip2 filter is in writing mode, you can't read."); | ||
120 | |||
121 | int nRead = 0; | ||
122 | int nReadTotal = bzState.total_out_lo32; | ||
123 | bzState.next_out = (char *)pData; | ||
124 | bzState.avail_out = nBytes; | ||
125 | for(;;) | ||
126 | { | ||
127 | int ret = BZ2_bzDecompress( &bzState ); | ||
128 | |||
129 | nReadTotal += nRead-bzState.avail_out; | ||
130 | |||
131 | if( ret == BZ_STREAM_END ) | ||
132 | { | ||
133 | if( bzState.avail_in > 0 ) | ||
134 | { | ||
135 | if( rNext.isSeekable() ) | ||
136 | { | ||
137 | rNext.seek( -bzState.avail_in ); | ||
138 | } | ||
139 | } | ||
140 | return nBytes-bzState.avail_out; | ||
141 | } | ||
142 | bzError( ret ); | ||
143 | |||
144 | if( bzState.avail_out ) | ||
145 | { | ||
146 | if( bzState.avail_in == 0 ) | ||
147 | { | ||
148 | nRead = rNext.read( pBuf, nBufSize ); | ||
149 | bzState.next_in = pBuf; | ||
150 | bzState.avail_in = nRead; | ||
151 | } | ||
152 | } | ||
153 | else | ||
154 | { | ||
155 | return nBytes-bzState.avail_out; | ||
156 | } | ||
157 | } | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | size_t Bu::BZip2::write( const void *pData, size_t nBytes ) | ||
162 | { | ||
163 | if( !bzState.state ) | ||
164 | { | ||
165 | bReading = false; | ||
166 | BZ2_bzCompressInit( &bzState, nCompression, 0, 30 ); | ||
167 | } | ||
168 | if( bReading == true ) | ||
169 | throw ExceptionBase("This bzip2 filter is in reading mode, you can't write."); | ||
170 | |||
171 | size_t sTotalOut = 0; | ||
172 | bzState.next_in = (char *)pData; | ||
173 | bzState.avail_in = nBytes; | ||
174 | for(;;) | ||
175 | { | ||
176 | bzState.avail_out = nBufSize; | ||
177 | bzState.next_out = pBuf; | ||
178 | |||
179 | bzError( BZ2_bzCompress( &bzState, BZ_RUN ) ); | ||
180 | |||
181 | if( bzState.avail_out < nBufSize ) | ||
182 | { | ||
183 | sTotalOut += rNext.write( pBuf, nBufSize-bzState.avail_out ); | ||
184 | } | ||
185 | if( bzState.avail_in == 0 ) | ||
186 | break; | ||
187 | } | ||
188 | |||
189 | return sTotalOut; | ||
190 | } | ||
191 | |||
192 | bool Bu::BZip2::isOpen() | ||
193 | { | ||
194 | return (bzState.state != NULL); | ||
195 | } | ||
196 | |||
diff --git a/src/bzip2.h b/src/bzip2.h new file mode 100644 index 0000000..0a111e8 --- /dev/null +++ b/src/bzip2.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef BU_BZIP2_H | ||
2 | #define BU_BZIP2_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include <bzlib.h> | ||
6 | |||
7 | #include "bu/filter.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | /** | ||
12 | * | ||
13 | */ | ||
14 | class BZip2 : public Bu::Filter | ||
15 | { | ||
16 | public: | ||
17 | BZip2( Bu::Stream &rNext, int nCompression=9 ); | ||
18 | virtual ~BZip2(); | ||
19 | |||
20 | virtual void start(); | ||
21 | virtual size_t stop(); | ||
22 | virtual size_t read( void *pBuf, size_t nBytes ); | ||
23 | virtual size_t write( const void *pBuf, size_t nBytes ); | ||
24 | |||
25 | virtual bool isOpen(); | ||
26 | |||
27 | private: | ||
28 | void bzError( int code ); | ||
29 | bz_stream bzState; | ||
30 | bool bReading; | ||
31 | int nCompression; | ||
32 | char *pBuf; | ||
33 | uint32_t nBufSize; | ||
34 | }; | ||
35 | } | ||
36 | |||
37 | #endif | ||
diff --git a/src/client.cpp b/src/client.cpp new file mode 100644 index 0000000..8077b3d --- /dev/null +++ b/src/client.cpp | |||
@@ -0,0 +1,206 @@ | |||
1 | #include "bu/client.h" | ||
2 | #include "bu/socket.h" | ||
3 | #include <stdlib.h> | ||
4 | #include <errno.h> | ||
5 | #include "bu/exceptions.h" | ||
6 | #include "bu/protocol.h" | ||
7 | |||
8 | /** Read buffer size. */ | ||
9 | #define RBS (1024*2) | ||
10 | |||
11 | Bu::Client::Client( Bu::Socket *pSocket ) : | ||
12 | pSocket( pSocket ), | ||
13 | pProto( NULL ), | ||
14 | nRBOffset( 0 ) | ||
15 | { | ||
16 | } | ||
17 | |||
18 | Bu::Client::~Client() | ||
19 | { | ||
20 | } | ||
21 | |||
22 | void Bu::Client::processInput() | ||
23 | { | ||
24 | char buf[RBS]; | ||
25 | size_t nRead, nTotal=0; | ||
26 | |||
27 | for(;;) | ||
28 | { | ||
29 | nRead = pSocket->read( buf, nRead ); | ||
30 | if( nRead < 0 ) | ||
31 | { | ||
32 | throw Bu::ConnectionException( | ||
33 | excodeReadError, | ||
34 | "Read error: %s", | ||
35 | strerror( errno ) | ||
36 | ); | ||
37 | } | ||
38 | else if( nRead == 0 ) | ||
39 | { | ||
40 | break; | ||
41 | } | ||
42 | else | ||
43 | { | ||
44 | nTotal += nRead; | ||
45 | sReadBuf.append( buf, nRead ); | ||
46 | if( !pSocket->canRead() ) | ||
47 | break; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | if( nTotal == 0 ) | ||
52 | { | ||
53 | pSocket->close(); | ||
54 | } | ||
55 | |||
56 | if( pProto && nTotal ) | ||
57 | { | ||
58 | pProto->onNewData( this ); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | void Bu::Client::processOutput() | ||
63 | { | ||
64 | if( sWriteBuf.getSize() > 0 ) | ||
65 | { | ||
66 | pSocket->write( sWriteBuf.getStr(), sWriteBuf.getSize() ); | ||
67 | sWriteBuf.clear(); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | void Bu::Client::setProtocol( Protocol *pProto ) | ||
72 | { | ||
73 | this->pProto = pProto; | ||
74 | } | ||
75 | |||
76 | Bu::Protocol *Bu::Client::getProtocol() | ||
77 | { | ||
78 | return pProto; | ||
79 | } | ||
80 | |||
81 | void Bu::Client::clearProtocol() | ||
82 | { | ||
83 | pProto = NULL; | ||
84 | } | ||
85 | |||
86 | Bu::FString &Bu::Client::getInput() | ||
87 | { | ||
88 | return sReadBuf; | ||
89 | } | ||
90 | |||
91 | Bu::FString &Bu::Client::getOutput() | ||
92 | { | ||
93 | return sWriteBuf; | ||
94 | } | ||
95 | |||
96 | bool Bu::Client::isOpen() | ||
97 | { | ||
98 | if( !pSocket ) return false; | ||
99 | return pSocket->isOpen(); | ||
100 | } | ||
101 | |||
102 | void Bu::Client::write( const void *pData, int nBytes ) | ||
103 | { | ||
104 | sWriteBuf.append( (const char *)pData, nBytes ); | ||
105 | } | ||
106 | |||
107 | void Bu::Client::write( int8_t nData ) | ||
108 | { | ||
109 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
110 | } | ||
111 | |||
112 | void Bu::Client::write( int16_t nData ) | ||
113 | { | ||
114 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
115 | } | ||
116 | |||
117 | void Bu::Client::write( int32_t nData ) | ||
118 | { | ||
119 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
120 | } | ||
121 | |||
122 | void Bu::Client::write( int64_t nData ) | ||
123 | { | ||
124 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
125 | } | ||
126 | |||
127 | void Bu::Client::write( uint8_t nData ) | ||
128 | { | ||
129 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
130 | } | ||
131 | |||
132 | void Bu::Client::write( uint16_t nData ) | ||
133 | { | ||
134 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
135 | } | ||
136 | |||
137 | void Bu::Client::write( uint32_t nData ) | ||
138 | { | ||
139 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
140 | } | ||
141 | |||
142 | void Bu::Client::write( uint64_t nData ) | ||
143 | { | ||
144 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
145 | } | ||
146 | |||
147 | void Bu::Client::read( void *pData, int nBytes ) | ||
148 | { | ||
149 | memcpy( pData, sReadBuf.getStr()+nRBOffset, nBytes ); | ||
150 | nRBOffset += nBytes; | ||
151 | if( sReadBuf.getSize()-nRBOffset == 0 ) | ||
152 | { | ||
153 | sReadBuf.clear(); | ||
154 | nRBOffset = 0; | ||
155 | } | ||
156 | // This is an experimental threshold, maybe I'll make this configurable | ||
157 | // later on. | ||
158 | else if( | ||
159 | (sReadBuf.getSize() >= 1024 && nRBOffset >= sReadBuf.getSize()/2) || | ||
160 | (nRBOffset >= sReadBuf.getSize()/4) | ||
161 | ) | ||
162 | { | ||
163 | sReadBuf.trimFront( nRBOffset ); | ||
164 | nRBOffset = 0; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | void Bu::Client::peek( void *pData, int nBytes ) | ||
169 | { | ||
170 | memcpy( pData, sReadBuf.getStr()+nRBOffset, nBytes ); | ||
171 | } | ||
172 | |||
173 | void Bu::Client::seek( int nBytes ) | ||
174 | { | ||
175 | nRBOffset += nBytes; | ||
176 | if( sReadBuf.getSize()-nRBOffset == 0 ) | ||
177 | { | ||
178 | sReadBuf.clear(); | ||
179 | nRBOffset = 0; | ||
180 | } | ||
181 | // This is an experimental threshold, maybe I'll make this configurable | ||
182 | // later on. | ||
183 | else if( | ||
184 | (sReadBuf.getSize() >= 1024 && nRBOffset >= sReadBuf.getSize()/2) || | ||
185 | (nRBOffset >= sReadBuf.getSize()/4) | ||
186 | ) | ||
187 | { | ||
188 | sReadBuf.trimFront( nRBOffset ); | ||
189 | nRBOffset = 0; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | long Bu::Client::getInputSize() | ||
194 | { | ||
195 | return sReadBuf.getSize()-nRBOffset; | ||
196 | } | ||
197 | |||
198 | const Bu::Socket *Bu::Client::getSocket() const | ||
199 | { | ||
200 | return pSocket; | ||
201 | } | ||
202 | |||
203 | void Bu::Client::disconnect() | ||
204 | { | ||
205 | } | ||
206 | |||
diff --git a/src/client.h b/src/client.h new file mode 100644 index 0000000..5947521 --- /dev/null +++ b/src/client.h | |||
@@ -0,0 +1,63 @@ | |||
1 | #ifndef BU_CLIENT_H | ||
2 | #define BU_CLIENT_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | #include "bu/fstring.h" | ||
7 | |||
8 | namespace Bu | ||
9 | { | ||
10 | class Protocol; | ||
11 | class Socket; | ||
12 | |||
13 | /** | ||
14 | * | ||
15 | */ | ||
16 | class Client | ||
17 | { | ||
18 | public: | ||
19 | Client( Bu::Socket *pSocket ); | ||
20 | virtual ~Client(); | ||
21 | |||
22 | void processInput(); | ||
23 | void processOutput(); | ||
24 | |||
25 | Bu::FString &getInput(); | ||
26 | Bu::FString &getOutput(); | ||
27 | void write( const void *pData, int nBytes ); | ||
28 | void write( int8_t nData ); | ||
29 | void write( int16_t nData ); | ||
30 | void write( int32_t nData ); | ||
31 | void write( int64_t nData ); | ||
32 | void write( uint8_t nData ); | ||
33 | void write( uint16_t nData ); | ||
34 | void write( uint32_t nData ); | ||
35 | void write( uint64_t nData ); | ||
36 | void read( void *pData, int nBytes ); | ||
37 | void peek( void *pData, int nBytes ); | ||
38 | void seek( int nBytes ); | ||
39 | long getInputSize(); | ||
40 | |||
41 | void setProtocol( Protocol *pProto ); | ||
42 | Bu::Protocol *getProtocol(); | ||
43 | void clearProtocol(); | ||
44 | |||
45 | bool isOpen(); | ||
46 | |||
47 | const Bu::Socket *getSocket() const; | ||
48 | |||
49 | /** | ||
50 | *@todo Make this not suck. | ||
51 | */ | ||
52 | void disconnect(); | ||
53 | |||
54 | private: | ||
55 | Bu::Socket *pSocket; | ||
56 | Bu::Protocol *pProto; | ||
57 | Bu::FString sReadBuf; | ||
58 | int nRBOffset; | ||
59 | Bu::FString sWriteBuf; | ||
60 | }; | ||
61 | } | ||
62 | |||
63 | #endif | ||
diff --git a/src/entities/bu-class b/src/entities/bu-class new file mode 100644 index 0000000..7b25291 --- /dev/null +++ b/src/entities/bu-class | |||
@@ -0,0 +1,48 @@ | |||
1 | <?xml version="1.1" ?> | ||
2 | <entity desc="Basic cpp class, with optional parent class. (.cpp+.h)"> | ||
3 | <param name="name" required="yes" desc="Name of the class"/> | ||
4 | <param name="parent" required="no" desc="Name of the parent class"/> | ||
5 | <file | ||
6 | name="header" | ||
7 | filename="{=name:%tolower}.h" | ||
8 | >#ifndef {=name:%uccsplit:%toupper}_H | ||
9 | #define {=name:%uccsplit:%toupper}_H | ||
10 | |||
11 | #include <stdint.h> | ||
12 | |||
13 | {?parent:"#include \"bu/{=parent:%tolower}.h\" | ||
14 | |||
15 | "}namespace Bu | ||
16 | { | ||
17 | /** | ||
18 | * | ||
19 | */ | ||
20 | class {=name}{?parent:" : public {=parent}"} | ||
21 | { | ||
22 | public: | ||
23 | {=name}(); | ||
24 | virtual ~{=name}(); | ||
25 | |||
26 | private: | ||
27 | |||
28 | }; | ||
29 | } | ||
30 | |||
31 | #endif | ||
32 | </file> | ||
33 | <file | ||
34 | name="source" | ||
35 | filename="{=name:%tolower}.cpp" | ||
36 | >#include "bu/{=name:%tolower}.h" | ||
37 | |||
38 | using namespace Bu; | ||
39 | |||
40 | Bu::{=name}::{=name}() | ||
41 | { | ||
42 | } | ||
43 | |||
44 | Bu::{=name}::~{=name}() | ||
45 | { | ||
46 | } | ||
47 | </file> | ||
48 | </entity> | ||
diff --git a/src/exceptionbase.cpp b/src/exceptionbase.cpp index f3d22da..f6ec625 100644 --- a/src/exceptionbase.cpp +++ b/src/exceptionbase.cpp | |||
@@ -1,7 +1,7 @@ | |||
1 | #include "exceptionbase.h" | 1 | #include "exceptionbase.h" |
2 | #include <stdarg.h> | 2 | #include <stdarg.h> |
3 | 3 | ||
4 | ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() : | 4 | Bu::ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() : |
5 | nErrorCode( 0 ), | 5 | nErrorCode( 0 ), |
6 | sWhat( NULL ) | 6 | sWhat( NULL ) |
7 | { | 7 | { |
@@ -12,7 +12,7 @@ ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() : | |||
12 | va_end(ap); | 12 | va_end(ap); |
13 | } | 13 | } |
14 | 14 | ||
15 | ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() : | 15 | Bu::ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() : |
16 | nErrorCode( nCode ), | 16 | nErrorCode( nCode ), |
17 | sWhat( NULL ) | 17 | sWhat( NULL ) |
18 | { | 18 | { |
@@ -23,13 +23,13 @@ ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() : | |||
23 | va_end(ap); | 23 | va_end(ap); |
24 | } | 24 | } |
25 | 25 | ||
26 | ExceptionBase::ExceptionBase( int nCode ) throw() : | 26 | Bu::ExceptionBase::ExceptionBase( int nCode ) throw() : |
27 | nErrorCode( nCode ), | 27 | nErrorCode( nCode ), |
28 | sWhat( NULL ) | 28 | sWhat( NULL ) |
29 | { | 29 | { |
30 | } | 30 | } |
31 | 31 | ||
32 | ExceptionBase::~ExceptionBase() throw() | 32 | Bu::ExceptionBase::~ExceptionBase() throw() |
33 | { | 33 | { |
34 | if( sWhat ) | 34 | if( sWhat ) |
35 | { | 35 | { |
@@ -38,7 +38,7 @@ ExceptionBase::~ExceptionBase() throw() | |||
38 | } | 38 | } |
39 | } | 39 | } |
40 | 40 | ||
41 | void ExceptionBase::setWhat( const char *lpFormat, va_list &vargs ) | 41 | void Bu::ExceptionBase::setWhat( const char *lpFormat, va_list &vargs ) |
42 | { | 42 | { |
43 | if( sWhat ) delete[] sWhat; | 43 | if( sWhat ) delete[] sWhat; |
44 | int nSize; | 44 | int nSize; |
@@ -48,7 +48,7 @@ void ExceptionBase::setWhat( const char *lpFormat, va_list &vargs ) | |||
48 | vsnprintf( sWhat, nSize+1, lpFormat, vargs ); | 48 | vsnprintf( sWhat, nSize+1, lpFormat, vargs ); |
49 | } | 49 | } |
50 | 50 | ||
51 | void ExceptionBase::setWhat( const char *lpText ) | 51 | void Bu::ExceptionBase::setWhat( const char *lpText ) |
52 | { | 52 | { |
53 | if( sWhat ) delete[] sWhat; | 53 | if( sWhat ) delete[] sWhat; |
54 | int nSize; | 54 | int nSize; |
@@ -58,12 +58,12 @@ void ExceptionBase::setWhat( const char *lpText ) | |||
58 | strcpy( sWhat, lpText ); | 58 | strcpy( sWhat, lpText ); |
59 | } | 59 | } |
60 | 60 | ||
61 | const char *ExceptionBase::what() const throw() | 61 | const char *Bu::ExceptionBase::what() const throw() |
62 | { | 62 | { |
63 | return sWhat; | 63 | return sWhat; |
64 | } | 64 | } |
65 | 65 | ||
66 | int ExceptionBase::getErrorCode() | 66 | int Bu::ExceptionBase::getErrorCode() |
67 | { | 67 | { |
68 | return nErrorCode; | 68 | return nErrorCode; |
69 | } | 69 | } |
diff --git a/src/exceptionbase.h b/src/exceptionbase.h index 6f1eca7..24e4bbf 100644 --- a/src/exceptionbase.h +++ b/src/exceptionbase.h | |||
@@ -1,75 +1,84 @@ | |||
1 | #ifndef EXCEPTION_BASE_H | 1 | #ifndef BU_EXCEPTION_BASE_H |
2 | #define EXCEPTION_BASE_H | 2 | #define BU_EXCEPTION_BASE_H |
3 | 3 | ||
4 | #include <string> | 4 | #include <string> |
5 | #include <exception> | 5 | #include <exception> |
6 | #include <stdarg.h> | 6 | #include <stdarg.h> |
7 | 7 | ||
8 | /** | 8 | namespace Bu |
9 | * A generalized Exception base class. This is nice for making general and | ||
10 | * flexible child classes that can create new error code classes. | ||
11 | */ | ||
12 | class ExceptionBase : public std::exception | ||
13 | { | 9 | { |
14 | public: | ||
15 | /** | ||
16 | * Construct an exception with an error code of zero, but with a | ||
17 | * description. The use of this is not reccomended most of the time, it's | ||
18 | * generally best to include an error code with the exception so your | ||
19 | * program can handle the exception in a better way. | ||
20 | * @param sFormat The format of the text. See printf for more info. | ||
21 | */ | ||
22 | ExceptionBase( const char *sFormat, ... ) throw(); | ||
23 | |||
24 | /** | 10 | /** |
11 | * A generalized Exception base class. This is nice for making general and | ||
12 | * flexible child classes that can create new error code classes. | ||
13 | * | ||
14 | * In order to create your own exception class use these two lines. | ||
25 | * | 15 | * |
26 | * @param nCode | 16 | * in your header: subExceptionDecl( NewClassName ); |
27 | * @param sFormat | ||
28 | */ | ||
29 | ExceptionBase( int nCode, const char *sFormat, ... ) throw(); | ||
30 | |||
31 | /** | ||
32 | * | 17 | * |
33 | * @param nCode | 18 | * in your source: subExcpetienDef( NewClassName ); |
34 | * @return | ||
35 | */ | 19 | */ |
36 | ExceptionBase( int nCode=0 ) throw(); | 20 | class ExceptionBase : public std::exception |
37 | 21 | { | |
38 | /** | 22 | public: |
39 | * | 23 | /** |
40 | * @return | 24 | * Construct an exception with an error code of zero, but with a |
41 | */ | 25 | * description. The use of this is not reccomended most of the time, |
42 | virtual ~ExceptionBase() throw(); | 26 | * it's generally best to include an error code with the exception so |
27 | * your program can handle the exception in a better way. | ||
28 | * @param sFormat The format of the text. See printf for more info. | ||
29 | */ | ||
30 | ExceptionBase( const char *sFormat, ... ) throw(); | ||
31 | |||
32 | /** | ||
33 | * | ||
34 | * @param nCode | ||
35 | * @param sFormat | ||
36 | */ | ||
37 | ExceptionBase( int nCode, const char *sFormat, ... ) throw(); | ||
38 | |||
39 | /** | ||
40 | * | ||
41 | * @param nCode | ||
42 | * @return | ||
43 | */ | ||
44 | ExceptionBase( int nCode=0 ) throw(); | ||
45 | |||
46 | /** | ||
47 | * | ||
48 | * @return | ||
49 | */ | ||
50 | virtual ~ExceptionBase() throw(); | ||
43 | 51 | ||
44 | /** | 52 | /** |
45 | * | 53 | * |
46 | * @return | 54 | * @return |
47 | */ | 55 | */ |
48 | virtual const char *what() const throw(); | 56 | virtual const char *what() const throw(); |
49 | 57 | ||
50 | /** | 58 | /** |
51 | * | 59 | * |
52 | * @return | 60 | * @return |
53 | */ | 61 | */ |
54 | int getErrorCode(); | 62 | int getErrorCode(); |
55 | 63 | ||
56 | /** | 64 | /** |
57 | * | 65 | * |
58 | * @param lpFormat | 66 | * @param lpFormat |
59 | * @param vargs | 67 | * @param vargs |
60 | */ | 68 | */ |
61 | void setWhat( const char *lpFormat, va_list &vargs ); | 69 | void setWhat( const char *lpFormat, va_list &vargs ); |
62 | 70 | ||
63 | /** | 71 | /** |
64 | * | 72 | * |
65 | * @param lpText | 73 | * @param lpText |
66 | */ | 74 | */ |
67 | void setWhat( const char *lpText ); | 75 | void setWhat( const char *lpText ); |
68 | 76 | ||
69 | private: | 77 | private: |
70 | int nErrorCode; /**< The code for the error that occured. */ | 78 | int nErrorCode; /**< The code for the error that occured. */ |
71 | char *sWhat; /**< The text string telling people what went wrong. */ | 79 | char *sWhat; /**< The text string telling people what went wrong. */ |
72 | }; | 80 | }; |
81 | } | ||
73 | 82 | ||
74 | #define subExceptionDecl( name ) \ | 83 | #define subExceptionDecl( name ) \ |
75 | class name : public ExceptionBase \ | 84 | class name : public ExceptionBase \ |
diff --git a/src/exceptions.cpp b/src/exceptions.cpp index ce79a5e..50b95c3 100644 --- a/src/exceptions.cpp +++ b/src/exceptions.cpp | |||
@@ -1,8 +1,13 @@ | |||
1 | #include "exceptions.h" | 1 | #include "exceptions.h" |
2 | #include <stdarg.h> | 2 | #include <stdarg.h> |
3 | 3 | ||
4 | subExceptionDef( XmlException ) | 4 | namespace Bu |
5 | subExceptionDef( FileException ) | 5 | { |
6 | subExceptionDef( ConnectionException ) | 6 | subExceptionDef( XmlException ) |
7 | subExceptionDef( PluginException ) | 7 | subExceptionDef( TafException ) |
8 | 8 | subExceptionDef( FileException ) | |
9 | subExceptionDef( SocketException ) | ||
10 | subExceptionDef( ConnectionException ) | ||
11 | subExceptionDef( PluginException ) | ||
12 | subExceptionDef( UnsupportedException ) | ||
13 | } | ||
diff --git a/src/exceptions.h b/src/exceptions.h index 0ab2b15..b824b91 100644 --- a/src/exceptions.h +++ b/src/exceptions.h | |||
@@ -1,25 +1,32 @@ | |||
1 | #ifndef EXCEPTIONS_H | 1 | #ifndef BU_EXCEPTIONS_H |
2 | #define EXCEPTIONS_H | 2 | #define BU_EXCEPTIONS_H |
3 | 3 | ||
4 | #include "exceptionbase.h" | 4 | #include "exceptionbase.h" |
5 | #include <stdarg.h> | 5 | #include <stdarg.h> |
6 | 6 | ||
7 | subExceptionDecl( XmlException ) | 7 | namespace Bu |
8 | subExceptionDecl( FileException ) | ||
9 | subExceptionDecl( ConnectionException ) | ||
10 | subExceptionDecl( PluginException ) | ||
11 | |||
12 | enum eFileException | ||
13 | { | ||
14 | excodeEOF | ||
15 | }; | ||
16 | |||
17 | enum eConnectionException | ||
18 | { | 8 | { |
19 | excodeReadError, | 9 | subExceptionDecl( XmlException ) |
20 | excodeBadReadError, | 10 | subExceptionDecl( TafException ) |
21 | excodeConnectionClosed, | 11 | subExceptionDecl( FileException ) |
22 | excodeSocketTimeout | 12 | subExceptionDecl( SocketException ) |
23 | }; | 13 | subExceptionDecl( ConnectionException ) |
14 | subExceptionDecl( PluginException ) | ||
15 | subExceptionDecl( UnsupportedException ) | ||
16 | |||
17 | enum eFileException | ||
18 | { | ||
19 | excodeEOF | ||
20 | }; | ||
21 | |||
22 | enum eConnectionException | ||
23 | { | ||
24 | excodeReadError, | ||
25 | excodeWriteError, | ||
26 | excodeBadReadError, | ||
27 | excodeConnectionClosed, | ||
28 | excodeSocketTimeout | ||
29 | }; | ||
30 | } | ||
24 | 31 | ||
25 | #endif | 32 | #endif |
diff --git a/src/file.cpp b/src/file.cpp new file mode 100644 index 0000000..1a8bd08 --- /dev/null +++ b/src/file.cpp | |||
@@ -0,0 +1,158 @@ | |||
1 | #include "file.h" | ||
2 | #include "exceptions.h" | ||
3 | #include <errno.h> | ||
4 | #include <sys/types.h> | ||
5 | #include <sys/stat.h> | ||
6 | |||
7 | Bu::File::File( const char *sName, const char *sFlags ) | ||
8 | { | ||
9 | fh = fopen( sName, sFlags ); | ||
10 | if( fh == NULL ) | ||
11 | { | ||
12 | throw Bu::FileException( errno, strerror(errno) ); | ||
13 | } | ||
14 | } | ||
15 | |||
16 | Bu::File::File( const Bu::FString &sName, const char *sFlags ) | ||
17 | { | ||
18 | fh = fopen( sName.getStr(), sFlags ); | ||
19 | if( fh == NULL ) | ||
20 | { | ||
21 | throw Bu::FileException( errno, strerror(errno) ); | ||
22 | } | ||
23 | } | ||
24 | |||
25 | Bu::File::File( int fd, const char *sFlags ) | ||
26 | { | ||
27 | fh = fdopen( fd, sFlags ); | ||
28 | } | ||
29 | |||
30 | Bu::File::~File() | ||
31 | { | ||
32 | close(); | ||
33 | } | ||
34 | |||
35 | void Bu::File::close() | ||
36 | { | ||
37 | if( fh ) | ||
38 | { | ||
39 | fclose( fh ); | ||
40 | fh = NULL; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | size_t Bu::File::read( void *pBuf, size_t nBytes ) | ||
45 | { | ||
46 | if( !fh ) | ||
47 | throw FileException("File not open."); | ||
48 | |||
49 | int nAmnt = fread( pBuf, 1, nBytes, fh ); | ||
50 | |||
51 | //if( nAmnt == 0 ) | ||
52 | // throw FileException("End of file."); | ||
53 | |||
54 | return nAmnt; | ||
55 | } | ||
56 | |||
57 | size_t Bu::File::write( const void *pBuf, size_t nBytes ) | ||
58 | { | ||
59 | if( !fh ) | ||
60 | throw FileException("File not open."); | ||
61 | |||
62 | return fwrite( pBuf, 1, nBytes, fh ); | ||
63 | } | ||
64 | |||
65 | long Bu::File::tell() | ||
66 | { | ||
67 | if( !fh ) | ||
68 | throw FileException("File not open."); | ||
69 | |||
70 | return ftell( fh ); | ||
71 | } | ||
72 | |||
73 | void Bu::File::seek( long offset ) | ||
74 | { | ||
75 | if( !fh ) | ||
76 | throw FileException("File not open."); | ||
77 | |||
78 | fseek( fh, offset, SEEK_CUR ); | ||
79 | } | ||
80 | |||
81 | void Bu::File::setPos( long pos ) | ||
82 | { | ||
83 | if( !fh ) | ||
84 | throw FileException("File not open."); | ||
85 | |||
86 | fseek( fh, pos, SEEK_SET ); | ||
87 | } | ||
88 | |||
89 | void Bu::File::setPosEnd( long pos ) | ||
90 | { | ||
91 | if( !fh ) | ||
92 | throw FileException("File not open."); | ||
93 | |||
94 | fseek( fh, pos, SEEK_END ); | ||
95 | } | ||
96 | |||
97 | bool Bu::File::isEOS() | ||
98 | { | ||
99 | return feof( fh ); | ||
100 | } | ||
101 | |||
102 | bool Bu::File::canRead() | ||
103 | { | ||
104 | return true; | ||
105 | } | ||
106 | |||
107 | bool Bu::File::canWrite() | ||
108 | { | ||
109 | return true; | ||
110 | } | ||
111 | |||
112 | bool Bu::File::isReadable() | ||
113 | { | ||
114 | return true; | ||
115 | } | ||
116 | |||
117 | bool Bu::File::isWritable() | ||
118 | { | ||
119 | return true; | ||
120 | } | ||
121 | |||
122 | bool Bu::File::isSeekable() | ||
123 | { | ||
124 | return true; | ||
125 | } | ||
126 | |||
127 | bool Bu::File::isBlocking() | ||
128 | { | ||
129 | return true; | ||
130 | } | ||
131 | |||
132 | void Bu::File::setBlocking( bool bBlocking ) | ||
133 | { | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | #ifndef WIN32 | ||
138 | void Bu::File::truncate( long nSize ) | ||
139 | { | ||
140 | ftruncate( fileno( fh ), nSize ); | ||
141 | } | ||
142 | |||
143 | void Bu::File::chmod( mode_t t ) | ||
144 | { | ||
145 | fchmod( fileno( fh ), t ); | ||
146 | } | ||
147 | #endif | ||
148 | |||
149 | void Bu::File::flush() | ||
150 | { | ||
151 | fflush( fh ); | ||
152 | } | ||
153 | |||
154 | bool Bu::File::isOpen() | ||
155 | { | ||
156 | return (fh != NULL); | ||
157 | } | ||
158 | |||
diff --git a/src/file.h b/src/file.h new file mode 100644 index 0000000..d4e43eb --- /dev/null +++ b/src/file.h | |||
@@ -0,0 +1,78 @@ | |||
1 | #ifndef BU_FILE_H | ||
2 | #define BU_FILE_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | #include "bu/stream.h" | ||
7 | #include "bu/fstring.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | class File : public Bu::Stream | ||
12 | { | ||
13 | public: | ||
14 | File( const char *sName, const char *sFlags ); | ||
15 | File( const Bu::FString &sName, const char *sFlags ); | ||
16 | File( int fd, const char *sFlags ); | ||
17 | virtual ~File(); | ||
18 | |||
19 | virtual void close(); | ||
20 | virtual size_t read( void *pBuf, size_t nBytes ); | ||
21 | virtual size_t write( const void *pBuf, size_t nBytes ); | ||
22 | |||
23 | virtual long tell(); | ||
24 | virtual void seek( long offset ); | ||
25 | virtual void setPos( long pos ); | ||
26 | virtual void setPosEnd( long pos ); | ||
27 | virtual bool isEOS(); | ||
28 | virtual bool isOpen(); | ||
29 | |||
30 | virtual void flush(); | ||
31 | |||
32 | virtual bool canRead(); | ||
33 | virtual bool canWrite(); | ||
34 | |||
35 | virtual bool isReadable(); | ||
36 | virtual bool isWritable(); | ||
37 | virtual bool isSeekable(); | ||
38 | |||
39 | virtual bool isBlocking(); | ||
40 | virtual void setBlocking( bool bBlocking=true ); | ||
41 | |||
42 | /** | ||
43 | * Create a temp file and return its handle | ||
44 | *@param sName (Bu::FString) Give in the form: "/tmp/tmpfileXXXXXXXX" | ||
45 | * It will alter your (sName) setting the 'X's to random | ||
46 | * characters. | ||
47 | *@param sFlags (const char *) Standard file flags 'rb'... etc.. | ||
48 | *@returns (Bu::File) A file object representing your temp file. | ||
49 | */ | ||
50 | #ifndef WIN32 | ||
51 | inline static Bu::File tempFile( Bu::FString &sName, const char *sFlags ) | ||
52 | { | ||
53 | int afh_d = mkstemp( sName.getStr() ); | ||
54 | |||
55 | return Bu::File( afh_d, sFlags ); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * Set the size of the file to (nSize). You can either grow or shrink | ||
60 | * the file. | ||
61 | *@param nSize (long) The new size of the file. | ||
62 | */ | ||
63 | void truncate( long nSize ); | ||
64 | |||
65 | /** | ||
66 | * Change the file access permissions. | ||
67 | *@param t (mode_t) The new file access permissions. | ||
68 | */ | ||
69 | void chmod( mode_t t ); | ||
70 | #endif | ||
71 | |||
72 | private: | ||
73 | FILE *fh; | ||
74 | |||
75 | }; | ||
76 | } | ||
77 | |||
78 | #endif | ||
diff --git a/src/filter.cpp b/src/filter.cpp new file mode 100644 index 0000000..96a8694 --- /dev/null +++ b/src/filter.cpp | |||
@@ -0,0 +1,97 @@ | |||
1 | #include "bu/filter.h" | ||
2 | |||
3 | Bu::Filter::Filter( Bu::Stream &rNext ) : | ||
4 | rNext( rNext ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | Bu::Filter::~Filter() | ||
9 | { | ||
10 | //printf("-> Bu::Filter::~Filter()\n"); | ||
11 | } | ||
12 | /* | ||
13 | void Bu::Filter::start() | ||
14 | { | ||
15 | printf("-> Bu::Filter::start()\n"); | ||
16 | } | ||
17 | |||
18 | void Bu::Filter::stop() | ||
19 | { | ||
20 | }*/ | ||
21 | |||
22 | void Bu::Filter::close() | ||
23 | { | ||
24 | stop(); | ||
25 | rNext.close(); | ||
26 | } | ||
27 | |||
28 | long Bu::Filter::tell() | ||
29 | { | ||
30 | return rNext.tell(); | ||
31 | } | ||
32 | |||
33 | void Bu::Filter::seek( long offset ) | ||
34 | { | ||
35 | rNext.seek( offset ); | ||
36 | } | ||
37 | |||
38 | void Bu::Filter::setPos( long pos ) | ||
39 | { | ||
40 | rNext.setPos( pos ); | ||
41 | } | ||
42 | |||
43 | void Bu::Filter::setPosEnd( long pos ) | ||
44 | { | ||
45 | rNext.setPosEnd( pos ); | ||
46 | } | ||
47 | |||
48 | bool Bu::Filter::isEOS() | ||
49 | { | ||
50 | return rNext.isEOS(); | ||
51 | } | ||
52 | |||
53 | bool Bu::Filter::isOpen() | ||
54 | { | ||
55 | return rNext.isOpen(); | ||
56 | } | ||
57 | |||
58 | bool Bu::Filter::canRead() | ||
59 | { | ||
60 | return rNext.canRead(); | ||
61 | } | ||
62 | |||
63 | bool Bu::Filter::canWrite() | ||
64 | { | ||
65 | return rNext.canWrite(); | ||
66 | } | ||
67 | |||
68 | bool Bu::Filter::isReadable() | ||
69 | { | ||
70 | return rNext.isReadable(); | ||
71 | } | ||
72 | |||
73 | bool Bu::Filter::isWritable() | ||
74 | { | ||
75 | return rNext.isWritable(); | ||
76 | } | ||
77 | |||
78 | bool Bu::Filter::isSeekable() | ||
79 | { | ||
80 | return rNext.isSeekable(); | ||
81 | } | ||
82 | |||
83 | bool Bu::Filter::isBlocking() | ||
84 | { | ||
85 | return rNext.isBlocking(); | ||
86 | } | ||
87 | |||
88 | void Bu::Filter::setBlocking( bool bBlocking ) | ||
89 | { | ||
90 | rNext.setBlocking( bBlocking ); | ||
91 | } | ||
92 | |||
93 | void Bu::Filter::flush() | ||
94 | { | ||
95 | rNext.flush(); | ||
96 | } | ||
97 | |||
diff --git a/src/filter.h b/src/filter.h new file mode 100644 index 0000000..bd557b2 --- /dev/null +++ b/src/filter.h | |||
@@ -0,0 +1,65 @@ | |||
1 | #ifndef BU_FILTER_H | ||
2 | #define BU_FILTER_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | #include "bu/stream.h" | ||
7 | |||
8 | namespace Bu | ||
9 | { | ||
10 | /** | ||
11 | * Data filter base class. Each data filter should contain a read and write | ||
12 | * section. Effectively, the write applies the filter, the read un-applies | ||
13 | * the filter, if possible. For example, BZip2 is a filter that compresses | ||
14 | * on write and decompresses on read. All bi-directional filters should | ||
15 | * follow: x == read( write( x ) ) (byte-for-byte comparison) | ||
16 | * | ||
17 | * Also, all returned buffers should be owned by the filter, and deleted | ||
18 | * when the filter is deleted. This means that the output of a read or | ||
19 | * write operation must be used before the next call to read or write or the | ||
20 | * data will be destroyed. Also, the internal buffer may be changed or | ||
21 | * recreated between calls, so always get a new pointer from a call to | ||
22 | * read or write. | ||
23 | * | ||
24 | * The close function can also return data, so make sure to check for it, | ||
25 | * many filters such as compression filters will buffer data until they have | ||
26 | * enough to create a compression block, in these cases the leftover data | ||
27 | * will be returned by close. | ||
28 | */ | ||
29 | class Filter : public Bu::Stream | ||
30 | { | ||
31 | public: | ||
32 | Filter( Bu::Stream &rNext ); | ||
33 | virtual ~Filter(); | ||
34 | |||
35 | virtual void start()=0; | ||
36 | virtual size_t stop()=0; | ||
37 | virtual void close(); | ||
38 | virtual long tell(); | ||
39 | virtual void seek( long offset ); | ||
40 | virtual void setPos( long pos ); | ||
41 | virtual void setPosEnd( long pos ); | ||
42 | virtual bool isEOS(); | ||
43 | virtual bool isOpen(); | ||
44 | |||
45 | virtual void flush(); | ||
46 | |||
47 | virtual bool canRead(); | ||
48 | virtual bool canWrite(); | ||
49 | |||
50 | virtual bool isReadable(); | ||
51 | virtual bool isWritable(); | ||
52 | virtual bool isSeekable(); | ||
53 | |||
54 | virtual bool isBlocking(); | ||
55 | virtual void setBlocking( bool bBlocking=true ); | ||
56 | |||
57 | protected: | ||
58 | Bu::Stream &rNext; | ||
59 | |||
60 | private: | ||
61 | |||
62 | }; | ||
63 | } | ||
64 | |||
65 | #endif | ||
diff --git a/src/fstring.cpp b/src/fstring.cpp index 82d024d..f71d6c1 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp | |||
@@ -1,13 +1,20 @@ | |||
1 | #include "fstring.h" | 1 | #include "fstring.h" |
2 | #include "hash.h" | 2 | #include "hash.h" |
3 | 3 | ||
4 | template<> uint32_t __calcHashCode<FString>( const FString &k ) | 4 | template<> uint32_t Bu::__calcHashCode<Bu::FString>( const Bu::FString &k ) |
5 | { | 5 | { |
6 | return __calcHashCode( k.c_str() ); | 6 | return __calcHashCode( k.c_str() ); |
7 | } | 7 | } |
8 | 8 | ||
9 | template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ) | 9 | template<> bool Bu::__cmpHashKeys<Bu::FString>( |
10 | const Bu::FString &a, const Bu::FString &b ) | ||
10 | { | 11 | { |
11 | return a == b; | 12 | return a == b; |
12 | } | 13 | } |
13 | 14 | ||
15 | std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FString &val ) | ||
16 | { | ||
17 | os.write( val.getStr(), val.getSize() ); | ||
18 | return os; | ||
19 | } | ||
20 | |||
diff --git a/src/fstring.h b/src/fstring.h index c5397cc..1e1fc02 100644 --- a/src/fstring.h +++ b/src/fstring.h | |||
@@ -1,651 +1,903 @@ | |||
1 | #ifndef F_STRING_H | 1 | #ifndef BU_F_STRING_H |
2 | #define F_STRING_H | 2 | #define BU_F_STRING_H |
3 | 3 | ||
4 | #include <stdint.h> | 4 | #include <stdint.h> |
5 | #include <memory> | 5 | #include <memory> |
6 | #include "serializable.h" | 6 | #include "bu/archival.h" |
7 | #include "serializer.h" | 7 | #include "bu/archive.h" |
8 | #include "bu/hash.h" | ||
8 | 9 | ||
9 | template< typename chr > | 10 | #define min( a, b ) ((a<b)?(a):(b)) |
10 | struct FStringChunk | 11 | |
11 | { | 12 | namespace Bu |
12 | long nLength; | ||
13 | chr *pData; | ||
14 | FStringChunk *pNext; | ||
15 | }; | ||
16 | |||
17 | /** | ||
18 | * Flexible String class. This class was designed with string passing and | ||
19 | * generation in mind. Like the standard string class you can specify what | ||
20 | * datatype to use for each character. Unlike the standard string class, | ||
21 | * collection of appended and prepended terms is done lazily, making long | ||
22 | * operations that involve many appends very inexpensive. In addition internal | ||
23 | * ref-counting means that if you pass strings around between functions there's | ||
24 | * almost no overhead in time or memory since a reference is created and no | ||
25 | * data is actually copied. This also means that you never need to put any | ||
26 | * FBasicString into a ref-counting container class. | ||
27 | */ | ||
28 | template< typename chr, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > > | ||
29 | class FBasicString : public Serializable | ||
30 | { | 13 | { |
14 | template< typename chr > | ||
15 | struct FStringChunk | ||
16 | { | ||
17 | long nLength; | ||
18 | chr *pData; | ||
19 | FStringChunk *pNext; | ||
20 | }; | ||
21 | |||
22 | /** | ||
23 | * Flexible String class. This class was designed with string passing and | ||
24 | * generation in mind. Like the standard string class you can specify what | ||
25 | * datatype to use for each character. Unlike the standard string class, | ||
26 | * collection of appended and prepended terms is done lazily, making long | ||
27 | * operations that involve many appends very inexpensive. In addition internal | ||
28 | * ref-counting means that if you pass strings around between functions there's | ||
29 | * almost no overhead in time or memory since a reference is created and no | ||
30 | * data is actually copied. This also means that you never need to put any | ||
31 | * FBasicString into a ref-counting container class. | ||
32 | * | ||
33 | *@param chr (typename) Type of character (i.e. char) | ||
34 | *@param nMinSize (int) Chunk size (default: 256) | ||
35 | *@param chralloc (typename) Memory Allocator for chr | ||
36 | *@param chunkalloc (typename) Memory Allocator for chr chunks | ||
37 | */ | ||
38 | template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > > | ||
39 | class FBasicString : public Archival | ||
40 | { | ||
31 | #ifndef VALTEST | 41 | #ifndef VALTEST |
32 | #define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) ) | 42 | #define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) ) |
33 | #endif | 43 | #endif |
34 | private: | 44 | private: |
35 | typedef struct FStringChunk<chr> Chunk; | 45 | typedef struct FStringChunk<chr> Chunk; |
36 | typedef struct FBasicString<chr, chralloc, chunkalloc> MyType; | 46 | typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType; |
37 | 47 | ||
38 | public: | 48 | public: |
39 | FBasicString() : | 49 | FBasicString() : |
40 | nLength( 0 ), | 50 | nLength( 0 ), |
41 | pnRefs( NULL ), | 51 | pnRefs( NULL ), |
42 | pFirst( NULL ), | 52 | pFirst( NULL ), |
43 | pLast( NULL ) | 53 | pLast( NULL ) |
44 | { | 54 | { |
45 | } | 55 | } |
46 | 56 | ||
47 | FBasicString( const chr *pData ) : | 57 | FBasicString( const chr *pData ) : |
48 | nLength( 0 ), | 58 | nLength( 0 ), |
49 | pnRefs( NULL ), | 59 | pnRefs( NULL ), |
50 | pFirst( NULL ), | 60 | pFirst( NULL ), |
51 | pLast( NULL ) | 61 | pLast( NULL ) |
52 | { | 62 | { |
53 | append( pData ); | 63 | append( pData ); |
54 | } | 64 | } |
55 | |||
56 | FBasicString( const chr *pData, long nLength ) : | ||
57 | nLength( 0 ), | ||
58 | pnRefs( NULL ), | ||
59 | pFirst( NULL ), | ||
60 | pLast( NULL ) | ||
61 | { | ||
62 | append( pData, nLength ); | ||
63 | } | ||
64 | |||
65 | FBasicString( const MyType &rSrc ) : | ||
66 | nLength( 0 ), | ||
67 | pnRefs( NULL ), | ||
68 | pFirst( NULL ), | ||
69 | pLast( NULL ) | ||
70 | { | ||
71 | // Here we have no choice but to copy, since the other guy is a const. | ||
72 | // In the case that the source were flat, we could get a reference, it | ||
73 | // would make some things faster, but not matter in many other cases. | ||
74 | |||
75 | joinShare( rSrc ); | ||
76 | //copyFrom( rSrc ); | ||
77 | } | ||
78 | |||
79 | FBasicString( const MyType &rSrc, long nLength ) : | ||
80 | nLength( 0 ), | ||
81 | pnRefs( NULL ), | ||
82 | pFirst( NULL ), | ||
83 | pLast( NULL ) | ||
84 | { | ||
85 | append( rSrc.pFirst->pData, nLength ); | ||
86 | } | ||
87 | |||
88 | FBasicString( const MyType &rSrc, long nStart, long nLength ) : | ||
89 | nLength( 0 ), | ||
90 | pnRefs( NULL ), | ||
91 | pFirst( NULL ), | ||
92 | pLast( NULL ) | ||
93 | { | ||
94 | append( rSrc.pFirst->pData+nStart, nLength ); | ||
95 | } | ||
96 | |||
97 | FBasicString( long nSize ) : | ||
98 | nLength( nSize ), | ||
99 | pnRefs( NULL ), | ||
100 | pFirst( NULL ), | ||
101 | pLast( NULL ) | ||
102 | { | ||
103 | pFirst = pLast = newChunk( nSize ); | ||
104 | } | ||
105 | 65 | ||
106 | virtual ~FBasicString() | 66 | FBasicString( const chr *pData, long nLength ) : |
107 | { | 67 | nLength( 0 ), |
108 | clear(); | 68 | pnRefs( NULL ), |
109 | } | 69 | pFirst( NULL ), |
70 | pLast( NULL ) | ||
71 | { | ||
72 | append( pData, nLength ); | ||
73 | } | ||
110 | 74 | ||
111 | void append( const chr *pData ) | 75 | FBasicString( const MyType &rSrc ) : |
112 | { | 76 | nLength( 0 ), |
113 | long nLen; | 77 | pnRefs( NULL ), |
114 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); | 78 | pFirst( NULL ), |
115 | 79 | pLast( NULL ) | |
116 | Chunk *pNew = newChunk( nLen ); | 80 | { |
117 | cpy( pNew->pData, pData, nLen ); | 81 | // Here we have no choice but to copy, since the other guy is a const. |
82 | // In the case that the source were flat, we could get a reference, it | ||
83 | // would make some things faster, but not matter in many other cases. | ||
118 | 84 | ||
119 | appendChunk( pNew ); | 85 | joinShare( rSrc ); |
120 | } | 86 | //copyFrom( rSrc ); |
87 | } | ||
121 | 88 | ||
122 | void append( const chr *pData, long nLen ) | 89 | FBasicString( const MyType &rSrc, long nLength ) : |
123 | { | 90 | nLength( 0 ), |
124 | Chunk *pNew = newChunk( nLen ); | 91 | pnRefs( NULL ), |
92 | pFirst( NULL ), | ||
93 | pLast( NULL ) | ||
94 | { | ||
95 | append( rSrc.pFirst->pData, nLength ); | ||
96 | } | ||
125 | 97 | ||
126 | cpy( pNew->pData, pData, nLen ); | 98 | FBasicString( const MyType &rSrc, long nStart, long nLength ) : |
99 | nLength( 0 ), | ||
100 | pnRefs( NULL ), | ||
101 | pFirst( NULL ), | ||
102 | pLast( NULL ) | ||
103 | { | ||
104 | append( rSrc.pFirst->pData+nStart, nLength ); | ||
105 | } | ||
127 | 106 | ||
128 | appendChunk( pNew ); | 107 | FBasicString( long nSize ) : |
129 | } | 108 | nLength( nSize ), |
109 | pnRefs( NULL ), | ||
110 | pFirst( NULL ), | ||
111 | pLast( NULL ) | ||
112 | { | ||
113 | pFirst = pLast = newChunk( nSize ); | ||
114 | } | ||
130 | 115 | ||
131 | void prepend( const chr *pData ) | 116 | virtual ~FBasicString() |
132 | { | 117 | { |
133 | long nLen; | 118 | clear(); |
134 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); | 119 | } |
135 | |||
136 | Chunk *pNew = newChunk( nLen ); | ||
137 | cpy( pNew->pData, pData, nLen ); | ||
138 | 120 | ||
139 | prependChunk( pNew ); | 121 | /** |
140 | } | 122 | *@todo void append( const MyType & sData ) |
123 | */ | ||
141 | 124 | ||
142 | void prepend( const chr *pData, long nLen ) | 125 | /** |
143 | { | 126 | * Append data to your string. |
144 | Chunk *pNew = newChunk( nLen ); | 127 | *@param pData (const chr *) The data to append. |
145 | 128 | */ | |
146 | cpy( pNew->pData, pData, nLen ); | 129 | void append( const chr *pData ) |
130 | { | ||
131 | if( !pData ) return; | ||
132 | long nLen; | ||
133 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); | ||
134 | if( nLen == 0 ) | ||
135 | return; | ||
136 | |||
137 | Chunk *pNew = newChunk( nLen ); | ||
138 | cpy( pNew->pData, pData, nLen ); | ||
147 | 139 | ||
148 | prependChunk( pNew ); | 140 | appendChunk( pNew ); |
149 | } | 141 | } |
150 | 142 | ||
151 | void clear() | 143 | /** |
152 | { | 144 | * Append data to your string. |
153 | realClear(); | 145 | *@param pData (const chr *) The data to append. |
154 | } | 146 | *@param nLen (long) The length of the data to append. |
147 | */ | ||
148 | void append( const chr *pData, long nLen ) | ||
149 | { | ||
150 | if( nLen == 0 ) | ||
151 | return; | ||
155 | 152 | ||
156 | void resize( long nNewSize ) | 153 | Chunk *pNew = newChunk( nLen ); |
157 | { | 154 | |
158 | if( nLength == nNewSize ) | 155 | cpy( pNew->pData, pData, nLen ); |
159 | return; | ||
160 | |||
161 | flatten(); | ||
162 | |||
163 | Chunk *pNew = newChunk( nNewSize ); | ||
164 | long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength); | ||
165 | cpy( pNew->pData, pFirst->pData, nNewLen ); | ||
166 | pNew->pData[nNewLen] = (chr)0; | ||
167 | aChr.deallocate( pFirst->pData, pFirst->nLength+1 ); | ||
168 | aChunk.deallocate( pFirst, 1 ); | ||
169 | pFirst = pLast = pNew; | ||
170 | nLength = nNewSize; | ||
171 | } | ||
172 | |||
173 | long getSize() const | ||
174 | { | ||
175 | return nLength; | ||
176 | } | ||
177 | |||
178 | chr *getStr() | ||
179 | { | ||
180 | if( pFirst == NULL ) | ||
181 | return NULL; | ||
182 | |||
183 | flatten(); | ||
184 | return pFirst->pData; | ||
185 | } | ||
186 | |||
187 | const chr *getStr() const | ||
188 | { | ||
189 | if( pFirst == NULL ) | ||
190 | return NULL; | ||
191 | 156 | ||
192 | flatten(); | 157 | appendChunk( pNew ); |
193 | return pFirst->pData; | 158 | } |
194 | } | ||
195 | 159 | ||
196 | chr *c_str() | 160 | /** |
197 | { | 161 | * Append a single chr to your string. |
198 | if( pFirst == NULL ) | 162 | *@param cData (const chr &) The character to append. |
199 | return NULL; | 163 | */ |
200 | 164 | void append( const chr &cData ) | |
201 | flatten(); | 165 | { |
202 | return pFirst->pData; | 166 | append( &cData, 1 ); |
203 | } | 167 | } |
204 | |||
205 | const chr *c_str() const | ||
206 | { | ||
207 | if( pFirst == NULL ) | ||
208 | return NULL; | ||
209 | 168 | ||
210 | flatten(); | 169 | /** |
211 | return pFirst->pData; | 170 | * Prepend another FString to this one. |
212 | } | 171 | *@param sData (MyType &) The FString to prepend. |
172 | */ | ||
173 | void prepend( const MyType & sData ) | ||
174 | { | ||
175 | prepend( sData.getStr(), sData.getSize() ); | ||
176 | } | ||
213 | 177 | ||
214 | MyType &operator +=( const chr *pData ) | 178 | /** |
215 | { | 179 | * Prepend data to your string. |
216 | append( pData ); | 180 | *@param pData (const chr *) The data to prepend. |
181 | */ | ||
182 | void prepend( const chr *pData ) | ||
183 | { | ||
184 | long nLen; | ||
185 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); | ||
186 | |||
187 | Chunk *pNew = newChunk( nLen ); | ||
188 | cpy( pNew->pData, pData, nLen ); | ||
217 | 189 | ||
218 | return (*this); | 190 | prependChunk( pNew ); |
219 | } | 191 | } |
220 | |||
221 | MyType &operator +=( const MyType &rSrc ) | ||
222 | { | ||
223 | rSrc.flatten(); | ||
224 | append( rSrc.pFirst->pData, rSrc.nLength ); | ||
225 | 192 | ||
226 | return (*this); | 193 | /** |
227 | } | 194 | * Prepend data to your string. |
195 | *@param pData (const chr *) The data to prepend. | ||
196 | *@param nLen (long) The length of the data to prepend. | ||
197 | */ | ||
198 | void prepend( const chr *pData, long nLen ) | ||
199 | { | ||
200 | Chunk *pNew = newChunk( nLen ); | ||
201 | |||
202 | cpy( pNew->pData, pData, nLen ); | ||
228 | 203 | ||
229 | MyType &operator +=( const chr pData ) | 204 | prependChunk( pNew ); |
230 | { | 205 | } |
231 | chr tmp[2] = { pData, (chr)0 }; | ||
232 | append( tmp ); | ||
233 | 206 | ||
234 | return (*this); | 207 | /** |
235 | } | 208 | *@todo void prepend( const chr &cData ) |
209 | */ | ||
236 | 210 | ||
237 | MyType &operator =( const chr *pData ) | 211 | /** |
238 | { | 212 | * Clear all data from the string. |
239 | clear(); | 213 | */ |
240 | append( pData ); | 214 | void clear() |
215 | { | ||
216 | realClear(); | ||
217 | } | ||
241 | 218 | ||
242 | return (*this); | 219 | /** |
243 | } | 220 | * Force the string to resize |
221 | *@param nNewSize (long) The new size of the string. | ||
222 | */ | ||
223 | void resize( long nNewSize ) | ||
224 | { | ||
225 | if( nLength == nNewSize ) | ||
226 | return; | ||
244 | 227 | ||
245 | MyType &operator =( const MyType &rSrc ) | 228 | flatten(); |
246 | { | 229 | |
247 | //if( rSrc.isFlat() ) | 230 | Chunk *pNew = newChunk( nNewSize ); |
248 | //{ | 231 | long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength); |
249 | joinShare( rSrc ); | 232 | cpy( pNew->pData, pFirst->pData, nNewLen ); |
250 | //} | 233 | pNew->pData[nNewLen] = (chr)0; |
251 | //else | 234 | aChr.deallocate( pFirst->pData, pFirst->nLength+1 ); |
252 | //{ | 235 | aChunk.deallocate( pFirst, 1 ); |
253 | // copyFrom( rSrc ); | 236 | pFirst = pLast = pNew; |
254 | //} | 237 | nLength = nNewSize; |
255 | // | ||
256 | |||
257 | return (*this); | ||
258 | } | ||
259 | |||
260 | bool operator ==( const chr *pData ) const | ||
261 | { | ||
262 | if( pFirst == NULL ) { | ||
263 | if( pData == NULL ) | ||
264 | return true; | ||
265 | return false; | ||
266 | } | 238 | } |
267 | 239 | ||
268 | flatten(); | 240 | /** |
269 | const chr *a = pData; | 241 | * Get the current size of the string. |
270 | chr *b = pFirst->pData; | 242 | *@returns (long) The current size of the string. |
271 | for( ; *a!=(chr)0; a++, b++ ) | 243 | */ |
244 | long getSize() const | ||
272 | { | 245 | { |
273 | if( *a != *b ) | 246 | return nLength; |
274 | return false; | ||
275 | } | 247 | } |
248 | |||
249 | /** | ||
250 | * Get a pointer to the string array. | ||
251 | *@returns (chr *) The string data. | ||
252 | */ | ||
253 | chr *getStr() | ||
254 | { | ||
255 | if( pFirst == NULL ) | ||
256 | return NULL; | ||
276 | 257 | ||
277 | return true; | 258 | flatten(); |
278 | } | 259 | return pFirst->pData; |
279 | 260 | } | |
280 | bool operator ==( const MyType &pData ) const | 261 | |
281 | { | 262 | /** |
282 | if( pFirst == pData.pFirst ) | 263 | * Get a const pointer to the string array. |
283 | return true; | 264 | *@returns (const chr *) The string data. |
284 | if( pFirst == NULL ) | 265 | */ |
285 | return false; | 266 | const chr *getStr() const |
267 | { | ||
268 | if( pFirst == NULL ) | ||
269 | return NULL; | ||
270 | |||
271 | flatten(); | ||
272 | return pFirst->pData; | ||
273 | } | ||
286 | 274 | ||
287 | flatten(); | 275 | /** |
288 | pData.flatten(); | 276 | * (std::string compatability) Get a pointer to the string array. |
289 | const chr *a = pData.pFirst->pData; | 277 | *@returns (chr *) The string data. |
290 | chr *b = pFirst->pData; | 278 | */ |
291 | for( ; *a!=(chr)0; a++, b++ ) | 279 | chr *c_str() |
292 | { | 280 | { |
293 | if( *a != *b ) | 281 | if( pFirst == NULL ) |
294 | return false; | 282 | return NULL; |
283 | |||
284 | flatten(); | ||
285 | return pFirst->pData; | ||
295 | } | 286 | } |
287 | |||
288 | /** | ||
289 | * (std::string compatability) Get a const pointer to the string array. | ||
290 | *@returns (const chr *) The string data. | ||
291 | */ | ||
292 | const chr *c_str() const | ||
293 | { | ||
294 | if( pFirst == NULL ) | ||
295 | return NULL; | ||
296 | 296 | ||
297 | return true; | 297 | flatten(); |
298 | } | 298 | return pFirst->pData; |
299 | } | ||
299 | 300 | ||
300 | bool operator !=(const chr *pData ) const | 301 | /** |
301 | { | 302 | * Plus equals operator for FString. |
302 | return !(*this == pData); | 303 | *@param pData (const chr *) The data to append to your FString. |
303 | } | 304 | */ |
304 | 305 | MyType &operator +=( const chr *pData ) | |
305 | bool operator !=(const MyType &pData ) const | 306 | { |
306 | { | 307 | append( pData ); |
307 | return !(*this == pData); | ||
308 | } | ||
309 | 308 | ||
310 | chr &operator[]( long nIndex ) | 309 | return (*this); |
311 | { | 310 | } |
312 | flatten(); | 311 | |
312 | /** | ||
313 | * Plus equals operator for FString. | ||
314 | *@param pData (const MyType &) The FString to append to your FString. | ||
315 | */ | ||
316 | MyType &operator +=( const MyType &rSrc ) | ||
317 | { | ||
318 | if( rSrc.nLength == 0 ) | ||
319 | return (*this); | ||
320 | rSrc.flatten(); | ||
321 | append( rSrc.pFirst->pData, rSrc.nLength ); | ||
313 | 322 | ||
314 | return pFirst->pData[nIndex]; | 323 | return (*this); |
315 | } | 324 | } |
316 | |||
317 | const chr &operator[]( long nIndex ) const | ||
318 | { | ||
319 | flatten(); | ||
320 | 325 | ||
321 | return pFirst->pData[nIndex]; | 326 | /** |
322 | } | 327 | * Plus equals operator for FString. |
328 | *@param pData (const chr) The character to append to your FString. | ||
329 | */ | ||
330 | MyType &operator +=( const chr pData ) | ||
331 | { | ||
332 | append( &pData, 1 ); | ||
323 | 333 | ||
324 | bool isWS( long nIndex ) const | 334 | return (*this); |
325 | { | 335 | } |
326 | flatten(); | ||
327 | 336 | ||
328 | return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t' | 337 | /** |
329 | || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n'; | 338 | * Assignment operator. |
330 | } | 339 | *@param pData (const chr *) The character array to append to your |
340 | * FString. | ||
341 | */ | ||
342 | MyType &operator =( const chr *pData ) | ||
343 | { | ||
344 | clear(); | ||
345 | append( pData ); | ||
331 | 346 | ||
332 | bool isAlpha( long nIndex ) const | 347 | return (*this); |
333 | { | 348 | } |
334 | flatten(); | ||
335 | 349 | ||
336 | return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z') | 350 | /** |
337 | || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z'); | 351 | * Reset your FString to this character array. |
338 | } | 352 | *@param pData (const chr *) The character array to set your FString to. |
353 | */ | ||
354 | void set( const chr *pData ) | ||
355 | { | ||
356 | clear(); | ||
357 | append( pData ); | ||
358 | } | ||
339 | 359 | ||
340 | void toLower() | 360 | /** |
341 | { | 361 | * Reset your FString to this character array. |
342 | flatten(); | 362 | *@param pData (const chr *) The character array to set your FString to. |
343 | unShare(); | 363 | *@param nSize (long) The length of the inputted character array. |
364 | */ | ||
365 | void set( const chr *pData, long nSize ) | ||
366 | { | ||
367 | clear(); | ||
368 | append( pData, nSize ); | ||
369 | } | ||
344 | 370 | ||
345 | for( long j = 0; j < nLength; j++ ) | 371 | /** |
372 | * Assignment operator. | ||
373 | *@param rSrc (const MyType &) The FString to set your FString to. | ||
374 | */ | ||
375 | MyType &operator =( const MyType &rSrc ) | ||
346 | { | 376 | { |
347 | if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' ) | 377 | //if( rSrc.isFlat() ) |
348 | pFirst->pData[j] -= 'A'-'a'; | 378 | //{ |
379 | joinShare( rSrc ); | ||
380 | //} | ||
381 | //else | ||
382 | //{ | ||
383 | // copyFrom( rSrc ); | ||
384 | //} | ||
385 | // | ||
386 | |||
387 | return (*this); | ||
349 | } | 388 | } |
350 | } | 389 | |
390 | /** | ||
391 | * Equals comparison operator. | ||
392 | *@param pData (const chr *) The character array to compare your FString | ||
393 | * to. | ||
394 | */ | ||
395 | bool operator ==( const chr *pData ) const | ||
396 | { | ||
397 | if( pFirst == NULL ) { | ||
398 | if( pData == NULL ) | ||
399 | return true; | ||
400 | return false; | ||
401 | } | ||
351 | 402 | ||
352 | void toUpper() | 403 | flatten(); |
353 | { | 404 | const chr *a = pData; |
354 | flatten(); | 405 | chr *b = pFirst->pData; |
355 | unShare(); | 406 | for( ; *a!=(chr)0; a++, b++ ) |
407 | { | ||
408 | if( *a != *b ) | ||
409 | return false; | ||
410 | } | ||
356 | 411 | ||
357 | for( long j = 0; j < nLength; j++ ) | 412 | return true; |
413 | } | ||
414 | |||
415 | /** | ||
416 | * Equals comparison operator. | ||
417 | *@param pData (const MyType &) The FString to compare your FString to. | ||
418 | */ | ||
419 | bool operator ==( const MyType &pData ) const | ||
358 | { | 420 | { |
359 | if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' ) | 421 | if( pFirst == pData.pFirst ) |
360 | pFirst->pData[j] += 'A'-'a'; | 422 | return true; |
423 | if( pFirst == NULL ) | ||
424 | return false; | ||
425 | |||
426 | flatten(); | ||
427 | pData.flatten(); | ||
428 | const chr *a = pData.pFirst->pData; | ||
429 | chr *b = pFirst->pData; | ||
430 | for( ; *a!=(chr)0; a++, b++ ) | ||
431 | { | ||
432 | if( *a != *b ) | ||
433 | return false; | ||
434 | } | ||
435 | |||
436 | return true; | ||
361 | } | 437 | } |
362 | } | ||
363 | 438 | ||
364 | void serialize( class Serializer &ar ) | 439 | /** |
365 | { | 440 | * Not equals comparison operator. |
366 | if( ar.isLoading() ) | 441 | *@param pData (const chr *) The character array to compare your FString |
442 | * to. | ||
443 | */ | ||
444 | bool operator !=(const chr *pData ) const | ||
367 | { | 445 | { |
368 | clear(); | 446 | return !(*this == pData); |
369 | long nLen; | 447 | } |
370 | ar >> nLen; | ||
371 | 448 | ||
372 | Chunk *pNew = newChunk( nLen ); | 449 | /** |
373 | ar.read( pNew->pData, nLen*sizeof(chr) ); | 450 | * Not equals comparison operator. |
374 | appendChunk( pNew ); | 451 | *@param pData (const MyType &) The FString to compare your FString to. |
452 | */ | ||
453 | bool operator !=(const MyType &pData ) const | ||
454 | { | ||
455 | return !(*this == pData); | ||
375 | } | 456 | } |
376 | else | 457 | |
458 | /** | ||
459 | * Indexing operator | ||
460 | *@param nIndex (long) The index of the character you want. | ||
461 | *@returns (chr &) The character at position (nIndex). | ||
462 | */ | ||
463 | chr &operator[]( long nIndex ) | ||
377 | { | 464 | { |
378 | flatten(); | 465 | flatten(); |
379 | 466 | ||
380 | ar << nLength; | 467 | return pFirst->pData[nIndex]; |
381 | ar.write( pFirst->pData, nLength*sizeof(chr) ); | ||
382 | } | 468 | } |
383 | } | 469 | |
470 | /** | ||
471 | * Const indexing operator | ||
472 | *@param nIndex (long) The index of the character you want. | ||
473 | *@returns (const chr &) The character at position (nIndex). | ||
474 | */ | ||
475 | const chr &operator[]( long nIndex ) const | ||
476 | { | ||
477 | flatten(); | ||
384 | 478 | ||
385 | private: | 479 | return pFirst->pData[nIndex]; |
386 | void flatten() const | 480 | } |
387 | { | 481 | /* |
388 | if( isFlat() ) | 482 | operator const chr *() const |
389 | return; | 483 | { |
484 | if( !pFirst ) return NULL; | ||
485 | flatten(); | ||
486 | return pFirst->pData; | ||
487 | } | ||
488 | */ | ||
390 | 489 | ||
391 | if( pFirst == NULL ) | 490 | operator bool() const |
392 | return; | 491 | { |
492 | return (pFirst != NULL); | ||
493 | } | ||
393 | 494 | ||
394 | unShare(); | 495 | bool isSet() const |
496 | { | ||
497 | return (pFirst != NULL); | ||
498 | } | ||
395 | 499 | ||
396 | Chunk *pNew = newChunk( nLength ); | 500 | /** |
397 | chr *pos = pNew->pData; | 501 | * Is the character at index (nIndex) white space? |
398 | Chunk *i = pFirst; | 502 | *@param nIndex (long) The index of the character you want to check. |
399 | for(;;) | 503 | *@returns (bool) Is it white space? |
504 | */ | ||
505 | bool isWS( long nIndex ) const | ||
400 | { | 506 | { |
401 | cpy( pos, i->pData, i->nLength ); | 507 | flatten(); |
402 | pos += i->nLength; | 508 | |
403 | i = i->pNext; | 509 | return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t' |
404 | if( i == NULL ) | 510 | || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n'; |
405 | break; | ||
406 | } | 511 | } |
407 | realClear(); | ||
408 | 512 | ||
409 | pLast = pFirst = pNew; | 513 | /** |
410 | nLength = pNew->nLength; | 514 | * Is the character at index (nIndex) a letter? |
411 | } | 515 | *@param nIndex (long) The index of the character you want to check. |
412 | 516 | *@returns (bool) Is it a letter? | |
413 | void realClear() const | 517 | */ |
414 | { | 518 | bool isAlpha( long nIndex ) const |
415 | if( pFirst == NULL ) | 519 | { |
416 | return; | 520 | flatten(); |
417 | 521 | ||
418 | if( isShared() ) | 522 | return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z') |
523 | || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z'); | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * Convert your alpha characters to lower case. | ||
528 | */ | ||
529 | void toLower() | ||
419 | { | 530 | { |
420 | decRefs(); | 531 | flatten(); |
532 | unShare(); | ||
533 | |||
534 | for( long j = 0; j < nLength; j++ ) | ||
535 | { | ||
536 | if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' ) | ||
537 | pFirst->pData[j] -= 'A'-'a'; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | /** | ||
542 | * Convert your alpha characters to upper case. | ||
543 | */ | ||
544 | void toUpper() | ||
545 | { | ||
546 | flatten(); | ||
547 | unShare(); | ||
548 | |||
549 | for( long j = 0; j < nLength; j++ ) | ||
550 | { | ||
551 | if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' ) | ||
552 | pFirst->pData[j] += 'A'-'a'; | ||
553 | } | ||
554 | } | ||
555 | |||
556 | /** | ||
557 | * Find the index of the first occurrance of (sText) | ||
558 | *@param sText (const char *) The string to search for. | ||
559 | *@returns (long) The index of the first occurrance. -1 for not found. | ||
560 | */ | ||
561 | long find( const char *sText ) | ||
562 | { | ||
563 | long nTLen = strlen( sText ); | ||
564 | flatten(); | ||
565 | for( long j = 0; j < pFirst->nLength-nTLen; j++ ) | ||
566 | { | ||
567 | if( !strncmp( sText, pFirst->pData+j, nTLen ) ) | ||
568 | return j; | ||
569 | } | ||
570 | return -1; | ||
571 | } | ||
572 | |||
573 | /** | ||
574 | * Do a reverse search for (sText) | ||
575 | *@param sText (const char *) The string to search for. | ||
576 | *@returns (long) The index of the last occurrance. -1 for not found. | ||
577 | */ | ||
578 | long rfind( const char *sText ) | ||
579 | { | ||
580 | long nTLen = strlen( sText ); | ||
581 | flatten(); | ||
582 | for( long j = pFirst->nLength-nTLen-1; j >= 0; j-- ) | ||
583 | { | ||
584 | if( !strncmp( sText, pFirst->pData+j, nTLen ) ) | ||
585 | return j; | ||
586 | } | ||
587 | return -1; | ||
588 | } | ||
589 | |||
590 | /** | ||
591 | * Remove nAmnt bytes from the front of the string. This function | ||
592 | * operates in O(n) time and should be used sparingly. | ||
593 | */ | ||
594 | void trimFront( long nAmnt ) | ||
595 | { | ||
596 | long nNewLen = nLength - nAmnt; | ||
597 | flatten(); | ||
598 | Chunk *pNew = newChunk( nNewLen ); | ||
599 | cpy( pNew->pData, pFirst->pData, nNewLen ); | ||
600 | clear(); | ||
601 | appendChunk( pNew ); | ||
602 | } | ||
603 | |||
604 | /** | ||
605 | * Function the archiver calls to archive your FString. | ||
606 | *@param ar (Archive) The archive which is archiving your FString. | ||
607 | */ | ||
608 | void archive( class Archive &ar ) | ||
609 | { | ||
610 | if( ar.isLoading() ) | ||
611 | { | ||
612 | clear(); | ||
613 | long nLen; | ||
614 | ar >> nLen; | ||
615 | |||
616 | if( nLen > 0 ) | ||
617 | { | ||
618 | Chunk *pNew = newChunk( nLen ); | ||
619 | ar.read( pNew->pData, nLen*sizeof(chr) ); | ||
620 | appendChunk( pNew ); | ||
621 | } | ||
622 | } | ||
623 | else | ||
624 | { | ||
625 | flatten(); | ||
626 | |||
627 | ar << nLength; | ||
628 | if( nLength ) | ||
629 | ar.write( pFirst->pData, nLength*sizeof(chr) ); | ||
630 | } | ||
421 | } | 631 | } |
422 | else | 632 | |
633 | private: | ||
634 | void flatten() const | ||
423 | { | 635 | { |
636 | if( isFlat() ) | ||
637 | return; | ||
638 | |||
639 | if( pFirst == NULL ) | ||
640 | return; | ||
641 | |||
642 | unShare(); | ||
643 | |||
644 | Chunk *pNew = newChunk( nLength ); | ||
645 | chr *pos = pNew->pData; | ||
424 | Chunk *i = pFirst; | 646 | Chunk *i = pFirst; |
425 | for(;;) | 647 | for(;;) |
426 | { | 648 | { |
427 | Chunk *n = i->pNext; | 649 | cpy( pos, i->pData, i->nLength ); |
428 | aChr.deallocate( i->pData, i->nLength+1 ); | 650 | pos += i->nLength; |
429 | aChunk.deallocate( i, 1 ); | 651 | i = i->pNext; |
430 | if( n == NULL ) | 652 | if( i == NULL ) |
431 | break; | 653 | break; |
432 | i = n; | ||
433 | } | 654 | } |
434 | pFirst = pLast = NULL; | 655 | realClear(); |
435 | nLength = 0; | 656 | |
657 | pLast = pFirst = pNew; | ||
658 | nLength = pNew->nLength; | ||
436 | } | 659 | } |
437 | } | ||
438 | |||
439 | void copyFrom( const FBasicString<chr, chralloc, chunkalloc> &rSrc ) | ||
440 | { | ||
441 | if( rSrc.pFirst == NULL ) | ||
442 | return; | ||
443 | 660 | ||
444 | decRefs(); | 661 | void realClear() const |
445 | |||
446 | Chunk *pNew = newChunk( rSrc.nLength ); | ||
447 | chr *pos = pNew->pData; | ||
448 | Chunk *i = rSrc.pFirst; | ||
449 | for(;;) | ||
450 | { | 662 | { |
451 | cpy( pos, i->pData, i->nLength ); | 663 | if( pFirst == NULL ) |
452 | pos += i->nLength; | 664 | return; |
453 | i = i->pNext; | ||
454 | if( i == NULL ) | ||
455 | break; | ||
456 | } | ||
457 | clear(); | ||
458 | 665 | ||
459 | appendChunk( pNew ); | 666 | if( isShared() ) |
460 | } | 667 | { |
461 | 668 | decRefs(); | |
462 | bool isFlat() const | 669 | } |
463 | { | 670 | else |
464 | return (pFirst == pLast); | 671 | { |
465 | } | 672 | Chunk *i = pFirst; |
466 | 673 | for(;;) | |
467 | bool isShared() const | 674 | { |
468 | { | 675 | Chunk *n = i->pNext; |
469 | return (pnRefs != NULL); | 676 | aChr.deallocate( i->pData, i->nLength+1 ); |
470 | } | 677 | aChunk.deallocate( i, 1 ); |
678 | if( n == NULL ) | ||
679 | break; | ||
680 | i = n; | ||
681 | } | ||
682 | pFirst = pLast = NULL; | ||
683 | nLength = 0; | ||
684 | } | ||
685 | } | ||
686 | |||
687 | void copyFrom( const FBasicString<chr, nMinSize, chralloc, chunkalloc> &rSrc ) | ||
688 | { | ||
689 | if( rSrc.pFirst == NULL ) | ||
690 | return; | ||
691 | |||
692 | decRefs(); | ||
471 | 693 | ||
472 | Chunk *newChunk() const | 694 | Chunk *pNew = newChunk( rSrc.nLength ); |
473 | { | 695 | chr *pos = pNew->pData; |
474 | Chunk *pNew = aChunk.allocate( 1 ); | 696 | Chunk *i = rSrc.pFirst; |
475 | pNew->pNext = NULL; | 697 | for(;;) |
476 | return pNew; | 698 | { |
477 | } | 699 | cpy( pos, i->pData, i->nLength ); |
478 | 700 | pos += i->nLength; | |
479 | Chunk *newChunk( long nLen ) const | 701 | i = i->pNext; |
480 | { | 702 | if( i == NULL ) |
481 | Chunk *pNew = aChunk.allocate( 1 ); | 703 | break; |
482 | pNew->pNext = NULL; | 704 | } |
483 | pNew->nLength = nLen; | 705 | clear(); |
484 | pNew->pData = aChr.allocate( nLen+1 ); | ||
485 | pNew->pData[nLen] = (chr)0; | ||
486 | return pNew; | ||
487 | } | ||
488 | |||
489 | void appendChunk( Chunk *pNewChunk ) | ||
490 | { | ||
491 | unShare(); | ||
492 | 706 | ||
493 | if( pFirst == NULL ) | 707 | appendChunk( pNew ); |
494 | pLast = pFirst = pNewChunk; | 708 | } |
495 | else | 709 | |
710 | bool isFlat() const | ||
496 | { | 711 | { |
497 | pLast->pNext = pNewChunk; | 712 | return (pFirst == pLast); |
498 | pLast = pNewChunk; | ||
499 | } | 713 | } |
500 | 714 | ||
501 | nLength += pNewChunk->nLength; | 715 | bool isShared() const |
502 | } | 716 | { |
503 | 717 | return (pnRefs != NULL); | |
504 | void prependChunk( Chunk *pNewChunk ) | 718 | } |
505 | { | ||
506 | unShare(); | ||
507 | 719 | ||
508 | if( pFirst == NULL ) | 720 | Chunk *newChunk() const |
509 | pLast = pFirst = pNewChunk; | 721 | { |
510 | else | 722 | Chunk *pNew = aChunk.allocate( 1 ); |
723 | pNew->pNext = NULL; | ||
724 | return pNew; | ||
725 | } | ||
726 | |||
727 | Chunk *newChunk( long nLen ) const | ||
511 | { | 728 | { |
512 | pNewChunk->pNext = pFirst; | 729 | Chunk *pNew = aChunk.allocate( 1 ); |
513 | pFirst = pNewChunk; | 730 | pNew->pNext = NULL; |
731 | pNew->nLength = nLen; | ||
732 | pNew->pData = aChr.allocate( nLen+1 ); | ||
733 | pNew->pData[nLen] = (chr)0; | ||
734 | return pNew; | ||
514 | } | 735 | } |
515 | 736 | ||
516 | nLength += pNewChunk->nLength; | 737 | void appendChunk( Chunk *pNewChunk ) |
517 | } | 738 | { |
739 | unShare(); | ||
518 | 740 | ||
519 | void joinShare( MyType &rSrc ) | 741 | if( pFirst == NULL ) |
520 | { | 742 | pLast = pFirst = pNewChunk; |
521 | clear(); | 743 | else |
744 | { | ||
745 | pLast->pNext = pNewChunk; | ||
746 | pLast = pNewChunk; | ||
747 | } | ||
522 | 748 | ||
523 | if( !rSrc.isFlat() ) | 749 | nLength += pNewChunk->nLength; |
524 | rSrc.flatten(); | 750 | } |
751 | |||
752 | void prependChunk( Chunk *pNewChunk ) | ||
753 | { | ||
754 | unShare(); | ||
525 | 755 | ||
526 | rSrc.initCount(); | 756 | if( pFirst == NULL ) |
527 | pnRefs = rSrc.pnRefs; | 757 | pLast = pFirst = pNewChunk; |
528 | (*pnRefs)++; | 758 | else |
529 | nLength = rSrc.nLength; | 759 | { |
530 | pFirst = rSrc.pFirst; | 760 | pNewChunk->pNext = pFirst; |
531 | pLast = rSrc.pLast; | 761 | pFirst = pNewChunk; |
532 | } | 762 | } |
533 | |||
534 | void joinShare( const MyType &rSrc ) | ||
535 | { | ||
536 | clear(); | ||
537 | 763 | ||
538 | rSrc.flatten(); | 764 | nLength += pNewChunk->nLength; |
765 | } | ||
539 | 766 | ||
540 | if( !rSrc.isShared() ) | 767 | void joinShare( MyType &rSrc ) |
541 | { | 768 | { |
542 | rSrc.pnRefs = new uint32_t; | 769 | clear(); |
543 | (*rSrc.pnRefs) = 1; | 770 | |
771 | if( !rSrc.isFlat() ) | ||
772 | rSrc.flatten(); | ||
773 | |||
774 | rSrc.initCount(); | ||
775 | pnRefs = rSrc.pnRefs; | ||
776 | (*pnRefs)++; | ||
777 | nLength = rSrc.nLength; | ||
778 | pFirst = rSrc.pFirst; | ||
779 | pLast = rSrc.pLast; | ||
544 | } | 780 | } |
545 | pnRefs = rSrc.pnRefs; | 781 | |
546 | (*pnRefs)++; | 782 | void joinShare( const MyType &rSrc ) |
547 | nLength = rSrc.nLength; | 783 | { |
548 | pFirst = rSrc.pFirst; | 784 | clear(); |
549 | pLast = rSrc.pLast; | ||
550 | } | ||
551 | 785 | ||
552 | /** | 786 | rSrc.flatten(); |
553 | * This takes an object that was shared and makes a copy of the base data | ||
554 | * that was being shared so that this copy can be changed. This should be | ||
555 | * added before any call that will change this object; | ||
556 | */ | ||
557 | void unShare() const | ||
558 | { | ||
559 | if( isShared() == false ) | ||
560 | return; | ||
561 | 787 | ||
562 | Chunk *pNew = newChunk( nLength ); | 788 | if( !rSrc.isShared() ) |
563 | chr *pos = pNew->pData; | 789 | { |
564 | Chunk *i = pFirst; | 790 | rSrc.pnRefs = new uint32_t; |
565 | for(;;) | 791 | (*rSrc.pnRefs) = 1; |
792 | } | ||
793 | pnRefs = rSrc.pnRefs; | ||
794 | (*pnRefs)++; | ||
795 | nLength = rSrc.nLength; | ||
796 | pFirst = rSrc.pFirst; | ||
797 | pLast = rSrc.pLast; | ||
798 | } | ||
799 | |||
800 | /** | ||
801 | * This takes an object that was shared and makes a copy of the base data | ||
802 | * that was being shared so that this copy can be changed. This should be | ||
803 | * added before any call that will change this object; | ||
804 | */ | ||
805 | void unShare() const | ||
566 | { | 806 | { |
567 | cpy( pos, i->pData, i->nLength ); | 807 | if( isShared() == false ) |
568 | pos += i->nLength; | 808 | return; |
569 | i = i->pNext; | 809 | if( pFirst == NULL ) |
570 | if( i == NULL ) | 810 | return; |
571 | break; | 811 | |
812 | Chunk *pNew = newChunk( nLength ); | ||
813 | chr *pos = pNew->pData; | ||
814 | Chunk *i = pFirst; | ||
815 | for(;;) | ||
816 | { | ||
817 | cpy( pos, i->pData, i->nLength ); | ||
818 | pos += i->nLength; | ||
819 | i = i->pNext; | ||
820 | if( i == NULL ) | ||
821 | break; | ||
822 | } | ||
823 | decRefs(); | ||
824 | pLast = pFirst = pNew; | ||
825 | nLength = pNew->nLength; | ||
572 | } | 826 | } |
573 | decRefs(); | ||
574 | pLast = pFirst = pNew; | ||
575 | nLength = pNew->nLength; | ||
576 | } | ||
577 | 827 | ||
578 | /** | 828 | /** |
579 | * This decrements our ref count and pulls us out of the share. If the ref | 829 | * This decrements our ref count and pulls us out of the share. If the ref |
580 | * count hits zero because of this, it destroys the share. This is not | 830 | * count hits zero because of this, it destroys the share. This is not |
581 | * safe to call on it's own, it's much better to call unShare. | 831 | * safe to call on it's own, it's much better to call unShare. |
582 | */ | 832 | */ |
583 | void decRefs() const | 833 | void decRefs() const |
584 | { | ||
585 | if( isShared() ) | ||
586 | { | 834 | { |
587 | (*pnRefs)--; | 835 | if( isShared() ) |
588 | if( (*pnRefs) == 0 ) | ||
589 | destroyShare(); | ||
590 | else | ||
591 | { | 836 | { |
592 | pnRefs = NULL; | 837 | (*pnRefs)--; |
593 | pFirst = NULL; | 838 | if( (*pnRefs) == 0 ) |
594 | pLast = NULL; | 839 | destroyShare(); |
595 | nLength = 0; | 840 | else |
841 | { | ||
842 | pnRefs = NULL; | ||
843 | pFirst = NULL; | ||
844 | pLast = NULL; | ||
845 | nLength = 0; | ||
846 | } | ||
596 | } | 847 | } |
597 | } | 848 | } |
598 | } | ||
599 | 849 | ||
600 | /** | 850 | /** |
601 | * While the unShare function removes an instance from a share, this | 851 | * While the unShare function removes an instance from a share, this |
602 | * function destroys the data that was in the share, removing the share | 852 | * function destroys the data that was in the share, removing the share |
603 | * itself. This should only be called when the refcount for the share has | 853 | * itself. This should only be called when the refcount for the share has |
604 | * or is about to reach zero. | 854 | * or is about to reach zero. |
605 | */ | 855 | */ |
606 | void destroyShare() const | 856 | void destroyShare() const |
607 | { | 857 | { |
608 | delete pnRefs; | 858 | delete pnRefs; |
609 | pnRefs = NULL; | 859 | pnRefs = NULL; |
610 | realClear(); | 860 | realClear(); |
611 | } | 861 | } |
612 | 862 | ||
613 | #ifdef VALTEST | 863 | #ifdef VALTEST |
614 | void cpy( chr *dest, const chr *src, long count ) const | 864 | void cpy( chr *dest, const chr *src, long count ) const |
615 | { | ||
616 | for( int j = 0; j < count; j++ ) | ||
617 | { | 865 | { |
618 | *dest = *src; | 866 | for( int j = 0; j < count; j++ ) |
619 | dest++; | 867 | { |
620 | src++; | 868 | *dest = *src; |
869 | dest++; | ||
870 | src++; | ||
871 | } | ||
621 | } | 872 | } |
622 | } | ||
623 | #endif | 873 | #endif |
624 | 874 | ||
625 | void initCount() const | 875 | void initCount() const |
626 | { | ||
627 | if( !isShared() ) | ||
628 | { | 876 | { |
629 | pnRefs = new uint32_t; | 877 | if( !isShared() ) |
630 | (*pnRefs) = 1; | 878 | { |
879 | pnRefs = new uint32_t; | ||
880 | (*pnRefs) = 1; | ||
881 | } | ||
631 | } | 882 | } |
632 | } | ||
633 | 883 | ||
634 | private: | 884 | private: |
635 | mutable long nLength; | 885 | mutable long nLength; |
636 | mutable uint32_t *pnRefs; | 886 | mutable uint32_t *pnRefs; |
637 | mutable Chunk *pFirst; | 887 | mutable Chunk *pFirst; |
638 | mutable Chunk *pLast; | 888 | mutable Chunk *pLast; |
639 | 889 | ||
640 | mutable chralloc aChr; | 890 | mutable chralloc aChr; |
641 | mutable chunkalloc aChunk; | 891 | mutable chunkalloc aChunk; |
642 | }; | 892 | }; |
643 | 893 | ||
644 | typedef FBasicString<char> FString; | 894 | typedef FBasicString<char> FString; |
645 | 895 | ||
646 | #include "hash.h" | 896 | template<> uint32_t __calcHashCode<FString>( const FString &k ); |
647 | template<> uint32_t __calcHashCode<FString>( const FString &k ); | 897 | template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ); |
648 | template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ); | 898 | } |
649 | 899 | ||
900 | #include <ostream> | ||
901 | std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FString &val ); | ||
650 | 902 | ||
651 | #endif | 903 | #endif |
diff --git a/src/hash.cpp b/src/hash.cpp index c52e6b1..a207c29 100644 --- a/src/hash.cpp +++ b/src/hash.cpp | |||
@@ -1,29 +1,29 @@ | |||
1 | #include "hash.h" | 1 | #include "hash.h" |
2 | 2 | ||
3 | subExceptionDef( HashException ) | 3 | namespace Bu { subExceptionDef( HashException ) } |
4 | 4 | ||
5 | template<> uint32_t __calcHashCode<int>( const int &k ) | 5 | template<> uint32_t Bu::__calcHashCode<int>( const int &k ) |
6 | { | 6 | { |
7 | return k; | 7 | return k; |
8 | } | 8 | } |
9 | 9 | ||
10 | template<> bool __cmpHashKeys<int>( const int &a, const int &b ) | 10 | template<> bool Bu::__cmpHashKeys<int>( const int &a, const int &b ) |
11 | { | 11 | { |
12 | return a == b; | 12 | return a == b; |
13 | } | 13 | } |
14 | 14 | ||
15 | template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k ) | 15 | template<> uint32_t Bu::__calcHashCode<unsigned int>( const unsigned int &k ) |
16 | { | 16 | { |
17 | return k; | 17 | return k; |
18 | } | 18 | } |
19 | 19 | ||
20 | template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b ) | 20 | template<> bool Bu::__cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b ) |
21 | { | 21 | { |
22 | return a == b; | 22 | return a == b; |
23 | } | 23 | } |
24 | 24 | ||
25 | template<> | 25 | template<> |
26 | uint32_t __calcHashCode<const char *>( const char * const &k ) | 26 | uint32_t Bu::__calcHashCode<const char *>( const char * const &k ) |
27 | { | 27 | { |
28 | if (k == NULL) | 28 | if (k == NULL) |
29 | { | 29 | { |
@@ -39,7 +39,7 @@ uint32_t __calcHashCode<const char *>( const char * const &k ) | |||
39 | return nPos; | 39 | return nPos; |
40 | } | 40 | } |
41 | 41 | ||
42 | template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b ) | 42 | template<> bool Bu::__cmpHashKeys<const char *>( const char * const &a, const char * const &b ) |
43 | { | 43 | { |
44 | if( a == b ) | 44 | if( a == b ) |
45 | return true; | 45 | return true; |
@@ -52,7 +52,7 @@ template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * | |||
52 | } | 52 | } |
53 | 53 | ||
54 | template<> | 54 | template<> |
55 | uint32_t __calcHashCode<char *>( char * const &k ) | 55 | uint32_t Bu::__calcHashCode<char *>( char * const &k ) |
56 | { | 56 | { |
57 | if (k == NULL) | 57 | if (k == NULL) |
58 | { | 58 | { |
@@ -68,7 +68,7 @@ uint32_t __calcHashCode<char *>( char * const &k ) | |||
68 | return nPos; | 68 | return nPos; |
69 | } | 69 | } |
70 | 70 | ||
71 | template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b ) | 71 | template<> bool Bu::__cmpHashKeys<char *>( char * const &a, char * const &b ) |
72 | { | 72 | { |
73 | if( a == b ) | 73 | if( a == b ) |
74 | return true; | 74 | return true; |
@@ -80,7 +80,7 @@ template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b ) | |||
80 | return false; | 80 | return false; |
81 | } | 81 | } |
82 | 82 | ||
83 | template<> uint32_t __calcHashCode<std::string>( const std::string &k ) | 83 | template<> uint32_t Bu::__calcHashCode<std::string>( const std::string &k ) |
84 | { | 84 | { |
85 | std::string::size_type j, sz = k.size(); | 85 | std::string::size_type j, sz = k.size(); |
86 | const char *s = k.c_str(); | 86 | const char *s = k.c_str(); |
@@ -94,20 +94,8 @@ template<> uint32_t __calcHashCode<std::string>( const std::string &k ) | |||
94 | return nPos; | 94 | return nPos; |
95 | } | 95 | } |
96 | 96 | ||
97 | template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b ) | 97 | template<> bool Bu::__cmpHashKeys<std::string>( const std::string &a, const std::string &b ) |
98 | { | 98 | { |
99 | return a == b; | 99 | return a == b; |
100 | } | 100 | } |
101 | 101 | ||
102 | template<> uint32_t __calcHashCode<Hashable>( const Hashable &k ) | ||
103 | { | ||
104 | return 0; | ||
105 | //return k.getHashCode(); | ||
106 | } | ||
107 | |||
108 | template<> bool __cmpHashKeys<Hashable>( const Hashable &a, const Hashable &b ) | ||
109 | { | ||
110 | return false; | ||
111 | //return a.compareForHash( b ); | ||
112 | } | ||
113 | |||
@@ -1,745 +1,1071 @@ | |||
1 | #ifndef HASH_H | 1 | #ifndef BU_HASH_H |
2 | #define HASH_H | 2 | #define BU_HASH_H |
3 | 3 | ||
4 | #include <stddef.h> | 4 | #include <stddef.h> |
5 | #include <string.h> | 5 | #include <string.h> |
6 | #include <memory> | 6 | #include <memory> |
7 | #include <iostream> | 7 | #include <iostream> |
8 | #include <list> | 8 | #include <list> |
9 | #include "exceptionbase.h" | 9 | #include <utility> |
10 | #include "hashable.h" | 10 | #include "bu/exceptionbase.h" |
11 | #include "serializable.h" | 11 | #include "bu/list.h" |
12 | #include "serializer.h" | 12 | ///#include "archival.h" |
13 | ///#include "archive.h" | ||
13 | 14 | ||
14 | #define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) | 15 | #define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) |
15 | 16 | ||
16 | subExceptionDecl( HashException ) | 17 | namespace Bu |
17 | |||
18 | enum eHashException | ||
19 | { | 18 | { |
20 | excodeNotFilled | 19 | subExceptionDecl( HashException ) |
21 | }; | ||
22 | |||
23 | template<typename T> | ||
24 | uint32_t __calcHashCode( const T &k ); | ||
25 | |||
26 | template<typename T> | ||
27 | bool __cmpHashKeys( const T &a, const T &b ); | ||
28 | 20 | ||
29 | struct __calcNextTSize_fast | 21 | enum eHashException |
30 | { | ||
31 | uint32_t operator()( uint32_t nCapacity, uint32_t nFill, uint32_t nDeleted ) const | ||
32 | { | 22 | { |
33 | if( nDeleted >= nCapacity/2 ) | 23 | excodeNotFilled |
34 | return nCapacity; | 24 | }; |
35 | return nCapacity*2+1; | ||
36 | } | ||
37 | }; | ||
38 | 25 | ||
39 | 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> > | 26 | template<typename T> |
40 | class Hash; | 27 | uint32_t __calcHashCode( const T &k ); |
41 | 28 | ||
42 | 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> > | 29 | template<typename T> |
43 | struct HashProxy | 30 | bool __cmpHashKeys( const T &a, const T &b ); |
44 | { | ||
45 | friend class Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc>; | ||
46 | private: | ||
47 | HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, key *k, uint32_t nPos, uint32_t hash ) : | ||
48 | hsh( h ), | ||
49 | pKey( k ), | ||
50 | nPos( nPos ), | ||
51 | hash( hash ), | ||
52 | bFilled( false ) | ||
53 | { | ||
54 | } | ||
55 | 31 | ||
56 | HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, uint32_t nPos, _value *pValue ) : | 32 | struct __calcNextTSize_fast |
57 | hsh( h ), | ||
58 | nPos( nPos ), | ||
59 | pValue( pValue ), | ||
60 | bFilled( true ) | ||
61 | { | 33 | { |
62 | } | 34 | uint32_t operator()( uint32_t nCapacity, uint32_t nFill, uint32_t nDeleted ) const |
35 | { | ||
36 | if( nDeleted >= nCapacity/2 ) | ||
37 | return nCapacity; | ||
38 | return nCapacity*2+1; | ||
39 | } | ||
40 | }; | ||
63 | 41 | ||
64 | Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &hsh; | 42 | 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> > |
65 | key *pKey; | 43 | class Hash; |
66 | uint32_t nPos; | ||
67 | _value *pValue; | ||
68 | uint32_t hash; | ||
69 | bool bFilled; | ||
70 | 44 | ||
71 | public: | 45 | 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> > |
72 | operator _value &() | 46 | struct HashProxy |
73 | { | 47 | { |
74 | if( bFilled == false ) | 48 | friend class Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc>; |
75 | throw HashException( | 49 | private: |
76 | excodeNotFilled, | 50 | HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, key *k, uint32_t nPos, uint32_t hash ) : |
77 | "No data assosiated with that key." | 51 | hsh( h ), |
78 | ); | 52 | pKey( k ), |
79 | return *pValue; | 53 | nPos( nPos ), |
80 | } | 54 | hash( hash ), |
55 | bFilled( false ) | ||
56 | { | ||
57 | } | ||
81 | 58 | ||
82 | _value &value() | 59 | HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, uint32_t nPos, _value *pValue ) : |
83 | { | 60 | hsh( h ), |
84 | if( bFilled == false ) | 61 | nPos( nPos ), |
85 | throw HashException( | 62 | pValue( pValue ), |
86 | excodeNotFilled, | 63 | bFilled( true ) |
87 | "No data assosiated with that key." | 64 | { |
88 | ); | 65 | } |
89 | return *pValue; | ||
90 | } | ||
91 | 66 | ||
92 | bool isFilled() | 67 | Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &hsh; |
93 | { | 68 | key *pKey; |
94 | return bFilled; | 69 | uint32_t nPos; |
95 | } | 70 | _value *pValue; |
71 | uint32_t hash; | ||
72 | bool bFilled; | ||
96 | 73 | ||
97 | void erase() | 74 | public: |
98 | { | 75 | /** |
99 | if( bFilled ) | 76 | * Cast operator for HashProxy. |
77 | *@returns (value_type &) The value the HashProxy is pointing to. | ||
78 | */ | ||
79 | operator _value &() | ||
100 | { | 80 | { |
101 | hsh._erase( nPos ); | 81 | if( bFilled == false ) |
102 | hsh.onDelete(); | 82 | throw HashException( |
83 | excodeNotFilled, | ||
84 | "No data assosiated with that key." | ||
85 | ); | ||
86 | return *pValue; | ||
103 | } | 87 | } |
104 | } | ||
105 | 88 | ||
106 | _value operator=( _value nval ) | 89 | /** |
107 | { | 90 | * Direct function for retrieving a value out of the HashProxy. |
108 | if( bFilled ) | 91 | *@returns (value_type &) The value pointed to by this HashProxy. |
92 | */ | ||
93 | _value &value() | ||
109 | { | 94 | { |
110 | hsh.va.destroy( pValue ); | 95 | if( bFilled == false ) |
111 | hsh.va.construct( pValue, nval ); | 96 | throw HashException( |
112 | hsh.onUpdate(); | 97 | excodeNotFilled, |
98 | "No data assosiated with that key." | ||
99 | ); | ||
100 | return *pValue; | ||
113 | } | 101 | } |
114 | else | 102 | |
103 | /** | ||
104 | * Whether this HashProxy points to something real or not. | ||
105 | */ | ||
106 | bool isFilled() | ||
115 | { | 107 | { |
116 | hsh.fill( nPos, *pKey, nval, hash ); | 108 | return bFilled; |
117 | hsh.onInsert(); | ||
118 | } | 109 | } |
119 | 110 | ||
120 | return nval; | 111 | /** |
121 | } | 112 | * Erase the data pointed to by this HashProxy. |
113 | */ | ||
114 | void erase() | ||
115 | { | ||
116 | if( bFilled ) | ||
117 | { | ||
118 | hsh._erase( nPos ); | ||
119 | hsh.onDelete(); | ||
120 | } | ||
121 | } | ||
122 | 122 | ||
123 | _value *operator->() | 123 | /** |
124 | { | 124 | * Assign data to this point in the hash table. |
125 | if( bFilled == false ) | 125 | *@param nval (value_type) the data to assign. |
126 | throw HashException( | 126 | */ |
127 | excodeNotFilled, | 127 | _value operator=( _value nval ) |
128 | "No data assosiated with that key." | 128 | { |
129 | ); | 129 | if( bFilled ) |
130 | return pValue; | 130 | { |
131 | } | 131 | hsh.va.destroy( pValue ); |
132 | }; | 132 | hsh.va.construct( pValue, nval ); |
133 | hsh.onUpdate(); | ||
134 | } | ||
135 | else | ||
136 | { | ||
137 | hsh.fill( nPos, *pKey, nval, hash ); | ||
138 | hsh.onInsert(); | ||
139 | } | ||
133 | 140 | ||
134 | template<typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc > | 141 | return nval; |
135 | class Hash | 142 | } |
136 | { | ||
137 | friend struct HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>; | ||
138 | public: | ||
139 | Hash() : | ||
140 | nCapacity( 11 ), | ||
141 | nFilled( 0 ), | ||
142 | nDeleted( 0 ), | ||
143 | bFilled( NULL ), | ||
144 | bDeleted( NULL ), | ||
145 | aKeys( NULL ), | ||
146 | aValues( NULL ), | ||
147 | aHashCodes( NULL ) | ||
148 | { | ||
149 | nKeysSize = bitsToBytes( nCapacity ); | ||
150 | bFilled = ca.allocate( nKeysSize ); | ||
151 | bDeleted = ca.allocate( nKeysSize ); | ||
152 | clearBits(); | ||
153 | |||
154 | aHashCodes = ca.allocate( nCapacity ); | ||
155 | aKeys = ka.allocate( nCapacity ); | ||
156 | aValues = va.allocate( nCapacity ); | ||
157 | } | ||
158 | 143 | ||
159 | Hash( const Hash &src ) : | 144 | /** |
160 | nCapacity( src.nCapacity ), | 145 | * Pointer extraction operator. Access to members of data pointed to |
161 | nFilled( 0 ), | 146 | * by HashProxy. |
162 | nDeleted( 0 ), | 147 | *@returns (value_type *) |
163 | bFilled( NULL ), | 148 | */ |
164 | bDeleted( NULL ), | 149 | _value *operator->() |
165 | aKeys( NULL ), | 150 | { |
166 | aValues( NULL ), | 151 | if( bFilled == false ) |
167 | aHashCodes( NULL ) | 152 | throw HashException( |
168 | { | 153 | excodeNotFilled, |
169 | nKeysSize = bitsToBytes( nCapacity ); | 154 | "No data assosiated with that key." |
170 | bFilled = ca.allocate( nKeysSize ); | 155 | ); |
171 | bDeleted = ca.allocate( nKeysSize ); | 156 | return pValue; |
172 | clearBits(); | 157 | } |
158 | }; | ||
173 | 159 | ||
174 | aHashCodes = ca.allocate( nCapacity ); | 160 | /** |
175 | aKeys = ka.allocate( nCapacity ); | 161 | * Libbu Template Hash Table |
176 | aValues = va.allocate( nCapacity ); | 162 | *@param key (typename) The datatype of the hashtable keys |
163 | *@param value (typename) The datatype of the hashtable data | ||
164 | *@param sizecalc (typename) Functor to compute new table size on rehash | ||
165 | *@param keyalloc (typename) Memory allocator for hashtable keys | ||
166 | *@param valuealloc (typename) Memory allocator for hashtable values | ||
167 | *@param challoc (typename) Byte allocator for bitflags | ||
168 | */ | ||
169 | template<typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc > | ||
170 | class Hash | ||
171 | { | ||
172 | friend struct HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>; | ||
173 | public: | ||
174 | Hash() : | ||
175 | nCapacity( 11 ), | ||
176 | nFilled( 0 ), | ||
177 | nDeleted( 0 ), | ||
178 | bFilled( NULL ), | ||
179 | bDeleted( NULL ), | ||
180 | aKeys( NULL ), | ||
181 | aValues( NULL ), | ||
182 | aHashCodes( NULL ) | ||
183 | { | ||
184 | nKeysSize = bitsToBytes( nCapacity ); | ||
185 | bFilled = ca.allocate( nKeysSize ); | ||
186 | bDeleted = ca.allocate( nKeysSize ); | ||
187 | clearBits(); | ||
188 | |||
189 | aHashCodes = ca.allocate( nCapacity ); | ||
190 | aKeys = ka.allocate( nCapacity ); | ||
191 | aValues = va.allocate( nCapacity ); | ||
192 | } | ||
177 | 193 | ||
178 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | 194 | Hash( const Hash &src ) : |
195 | nCapacity( src.nCapacity ), | ||
196 | nFilled( 0 ), | ||
197 | nDeleted( 0 ), | ||
198 | bFilled( NULL ), | ||
199 | bDeleted( NULL ), | ||
200 | aKeys( NULL ), | ||
201 | aValues( NULL ), | ||
202 | aHashCodes( NULL ) | ||
179 | { | 203 | { |
180 | if( src.isFilled( j ) ) | 204 | nKeysSize = bitsToBytes( nCapacity ); |
205 | bFilled = ca.allocate( nKeysSize ); | ||
206 | bDeleted = ca.allocate( nKeysSize ); | ||
207 | clearBits(); | ||
208 | |||
209 | aHashCodes = ca.allocate( nCapacity ); | ||
210 | aKeys = ka.allocate( nCapacity ); | ||
211 | aValues = va.allocate( nCapacity ); | ||
212 | |||
213 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
181 | { | 214 | { |
182 | insert( src.aKeys[j], src.aValues[j] ); | 215 | if( src.isFilled( j ) ) |
216 | { | ||
217 | insert( src.aKeys[j], src.aValues[j] ); | ||
218 | } | ||
183 | } | 219 | } |
184 | } | 220 | } |
185 | } | ||
186 | 221 | ||
187 | Hash &operator=( const Hash &src ) | 222 | /** |
188 | { | 223 | * Hashtable assignment operator. Clears this hashtable and |
189 | for( uint32_t j = 0; j < nCapacity; j++ ) | 224 | * copies RH into it. |
225 | */ | ||
226 | Hash &operator=( const Hash &src ) | ||
190 | { | 227 | { |
191 | if( isFilled( j ) ) | 228 | for( uint32_t j = 0; j < nCapacity; j++ ) |
192 | if( !isDeleted( j ) ) | 229 | { |
230 | if( isFilled( j ) ) | ||
231 | if( !isDeleted( j ) ) | ||
232 | { | ||
233 | va.destroy( &aValues[j] ); | ||
234 | ka.destroy( &aKeys[j] ); | ||
235 | } | ||
236 | } | ||
237 | va.deallocate( aValues, nCapacity ); | ||
238 | ka.deallocate( aKeys, nCapacity ); | ||
239 | ca.deallocate( bFilled, nKeysSize ); | ||
240 | ca.deallocate( bDeleted, nKeysSize ); | ||
241 | ca.deallocate( aHashCodes, nCapacity ); | ||
242 | |||
243 | nFilled = 0; | ||
244 | nDeleted = 0; | ||
245 | nCapacity = src.nCapacity; | ||
246 | nKeysSize = bitsToBytes( nCapacity ); | ||
247 | bFilled = ca.allocate( nKeysSize ); | ||
248 | bDeleted = ca.allocate( nKeysSize ); | ||
249 | clearBits(); | ||
250 | |||
251 | aHashCodes = ca.allocate( nCapacity ); | ||
252 | aKeys = ka.allocate( nCapacity ); | ||
253 | aValues = va.allocate( nCapacity ); | ||
254 | |||
255 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
256 | { | ||
257 | if( src.isFilled( j ) ) | ||
193 | { | 258 | { |
194 | va.destroy( &aValues[j] ); | 259 | insert( src.aKeys[j], src.aValues[j] ); |
195 | ka.destroy( &aKeys[j] ); | ||
196 | } | 260 | } |
197 | } | 261 | } |
198 | va.deallocate( aValues, nCapacity ); | ||
199 | ka.deallocate( aKeys, nCapacity ); | ||
200 | ca.deallocate( bFilled, nKeysSize ); | ||
201 | ca.deallocate( bDeleted, nKeysSize ); | ||
202 | ca.deallocate( aHashCodes, nCapacity ); | ||
203 | |||
204 | nFilled = 0; | ||
205 | nDeleted = 0; | ||
206 | nCapacity = src.nCapacity; | ||
207 | nKeysSize = bitsToBytes( nCapacity ); | ||
208 | bFilled = ca.allocate( nKeysSize ); | ||
209 | bDeleted = ca.allocate( nKeysSize ); | ||
210 | clearBits(); | ||
211 | 262 | ||
212 | aHashCodes = ca.allocate( nCapacity ); | 263 | return *this; |
213 | aKeys = ka.allocate( nCapacity ); | 264 | } |
214 | aValues = va.allocate( nCapacity ); | ||
215 | 265 | ||
216 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | 266 | virtual ~Hash() |
217 | { | 267 | { |
218 | if( src.isFilled( j ) ) | 268 | for( uint32_t j = 0; j < nCapacity; j++ ) |
219 | { | 269 | { |
220 | insert( src.aKeys[j], src.aValues[j] ); | 270 | if( isFilled( j ) ) |
271 | if( !isDeleted( j ) ) | ||
272 | { | ||
273 | va.destroy( &aValues[j] ); | ||
274 | ka.destroy( &aKeys[j] ); | ||
275 | } | ||
221 | } | 276 | } |
277 | va.deallocate( aValues, nCapacity ); | ||
278 | ka.deallocate( aKeys, nCapacity ); | ||
279 | ca.deallocate( bFilled, nKeysSize ); | ||
280 | ca.deallocate( bDeleted, nKeysSize ); | ||
281 | ca.deallocate( aHashCodes, nCapacity ); | ||
222 | } | 282 | } |
223 | 283 | ||
224 | return *this; | 284 | /** |
225 | } | 285 | * Get the current hash table capacity. (Changes at re-hash) |
226 | 286 | *@returns (uint32_t) The current capacity. | |
227 | virtual ~Hash() | 287 | */ |
228 | { | 288 | uint32_t getCapacity() |
229 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
230 | { | 289 | { |
231 | if( isFilled( j ) ) | 290 | return nCapacity; |
232 | if( !isDeleted( j ) ) | ||
233 | { | ||
234 | va.destroy( &aValues[j] ); | ||
235 | ka.destroy( &aKeys[j] ); | ||
236 | } | ||
237 | } | 291 | } |
238 | va.deallocate( aValues, nCapacity ); | ||
239 | ka.deallocate( aKeys, nCapacity ); | ||
240 | ca.deallocate( bFilled, nKeysSize ); | ||
241 | ca.deallocate( bDeleted, nKeysSize ); | ||
242 | ca.deallocate( aHashCodes, nCapacity ); | ||
243 | } | ||
244 | 292 | ||
245 | uint32_t getCapacity() | 293 | /** |
246 | { | 294 | * Get the number of hash locations spoken for. (Including |
247 | return nCapacity; | 295 | * not-yet-cleaned-up deleted items.) |
248 | } | 296 | *@returns (uint32_t) The current fill state. |
297 | */ | ||
298 | uint32_t getFill() | ||
299 | { | ||
300 | return nFilled; | ||
301 | } | ||
249 | 302 | ||
250 | uint32_t getFill() | 303 | /** |
251 | { | 304 | * Get the number of items stored in the hash table. |
252 | return nFilled; | 305 | *@returns (uint32_t) The number of items stored in the hash table. |
253 | } | 306 | */ |
307 | uint32_t size() | ||
308 | { | ||
309 | return nFilled-nDeleted; | ||
310 | } | ||
254 | 311 | ||
255 | uint32_t size() | 312 | /** |
256 | { | 313 | * Get the number of items which have been deleted, but not yet |
257 | return nFilled-nDeleted; | 314 | * cleaned up. |
258 | } | 315 | *@returns (uint32_t) The number of deleted items. |
316 | */ | ||
317 | uint32_t getDeleted() | ||
318 | { | ||
319 | return nDeleted; | ||
320 | } | ||
259 | 321 | ||
260 | uint32_t getDeleted() | 322 | /** |
261 | { | 323 | * Hash table index operator |
262 | return nDeleted; | 324 | *@param k (key_type) Key of data to be retrieved. |
263 | } | 325 | *@returns (HashProxy) Proxy pointing to the data. |
326 | */ | ||
327 | virtual HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc> operator[]( key k ) | ||
328 | { | ||
329 | uint32_t hash = __calcHashCode( k ); | ||
330 | bool bFill; | ||
331 | uint32_t nPos = probe( hash, k, bFill ); | ||
264 | 332 | ||
265 | virtual HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc> operator[]( key k ) | 333 | if( bFill ) |
266 | { | 334 | { |
267 | uint32_t hash = __calcHashCode( k ); | 335 | return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, nPos, &aValues[nPos] ); |
268 | bool bFill; | 336 | } |
269 | uint32_t nPos = probe( hash, k, bFill ); | 337 | else |
338 | { | ||
339 | return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, &k, nPos, hash ); | ||
340 | } | ||
341 | } | ||
270 | 342 | ||
271 | if( bFill ) | 343 | /** |
344 | * Insert a value (v) under key (k) into the hash table | ||
345 | *@param k (key_type) Key to list the value under. | ||
346 | *@param v (value_type) Value to store in the hash table. | ||
347 | */ | ||
348 | virtual void insert( key k, value v ) | ||
272 | { | 349 | { |
273 | return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, nPos, &aValues[nPos] ); | 350 | uint32_t hash = __calcHashCode( k ); |
351 | bool bFill; | ||
352 | uint32_t nPos = probe( hash, k, bFill ); | ||
353 | |||
354 | if( bFill ) | ||
355 | { | ||
356 | va.destroy( &aValues[nPos] ); | ||
357 | va.construct( &aValues[nPos], v ); | ||
358 | onUpdate(); | ||
359 | } | ||
360 | else | ||
361 | { | ||
362 | fill( nPos, k, v, hash ); | ||
363 | onInsert(); | ||
364 | } | ||
274 | } | 365 | } |
275 | else | 366 | |
367 | /** | ||
368 | * Remove a value from the hash table. | ||
369 | *@param k (key_type) The data under this key will be erased. | ||
370 | */ | ||
371 | virtual void erase( key k ) | ||
276 | { | 372 | { |
277 | return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, &k, nPos, hash ); | 373 | uint32_t hash = __calcHashCode( k ); |
374 | bool bFill; | ||
375 | uint32_t nPos = probe( hash, k, bFill ); | ||
376 | |||
377 | if( bFill ) | ||
378 | { | ||
379 | _erase( nPos ); | ||
380 | onDelete(); | ||
381 | } | ||
278 | } | 382 | } |
279 | } | ||
280 | 383 | ||
281 | virtual void insert( key k, value v ) | 384 | struct iterator; |
282 | { | ||
283 | uint32_t hash = __calcHashCode( k ); | ||
284 | bool bFill; | ||
285 | uint32_t nPos = probe( hash, k, bFill ); | ||
286 | 385 | ||
287 | if( bFill ) | 386 | /** |
387 | * Remove a value from the hash pointed to from an iterator. | ||
388 | *@param i (iterator &) The data to be erased. | ||
389 | */ | ||
390 | virtual void erase( struct iterator &i ) | ||
288 | { | 391 | { |
289 | va.destroy( &aValues[nPos] ); | 392 | if( this != &i.hsh ) |
290 | va.construct( &aValues[nPos], v ); | 393 | throw HashException("This iterator didn't come from this Hash."); |
291 | onUpdate(); | 394 | if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) |
395 | { | ||
396 | _erase( i.nPos ); | ||
397 | onDelete(); | ||
398 | } | ||
292 | } | 399 | } |
293 | else | 400 | |
401 | /** | ||
402 | * Remove all data from the hash table. | ||
403 | */ | ||
404 | virtual void clear() | ||
294 | { | 405 | { |
295 | fill( nPos, k, v, hash ); | 406 | for( uint32_t j = 0; j < nCapacity; j++ ) |
296 | onInsert(); | 407 | { |
408 | if( isFilled( j ) ) | ||
409 | if( !isDeleted( j ) ) | ||
410 | { | ||
411 | va.destroy( &aValues[j] ); | ||
412 | ka.destroy( &aKeys[j] ); | ||
413 | onDelete(); | ||
414 | } | ||
415 | } | ||
416 | |||
417 | clearBits(); | ||
297 | } | 418 | } |
298 | } | ||
299 | 419 | ||
300 | virtual void erase( key k ) | 420 | /** |
301 | { | 421 | * Get an item of data from the hash table. |
302 | uint32_t hash = __calcHashCode( k ); | 422 | *@param k (key_type) Key pointing to the data to be retrieved. |
303 | bool bFill; | 423 | *@returns (value_type &) The data pointed to by (k). |
304 | uint32_t nPos = probe( hash, k, bFill ); | 424 | */ |
425 | virtual value &get( key k ) | ||
426 | { | ||
427 | uint32_t hash = __calcHashCode( k ); | ||
428 | bool bFill; | ||
429 | uint32_t nPos = probe( hash, k, bFill ); | ||
305 | 430 | ||
306 | if( bFill ) | 431 | if( bFill ) |
432 | { | ||
433 | return aValues[nPos]; | ||
434 | } | ||
435 | else | ||
436 | { | ||
437 | throw HashException( | ||
438 | excodeNotFilled, | ||
439 | "No data assosiated with that key." | ||
440 | ); | ||
441 | } | ||
442 | } | ||
443 | |||
444 | /** | ||
445 | * Get a const item of data from the hash table. | ||
446 | *@param k (key_type) Key pointing to the data to be retrieved. | ||
447 | *@returns (const value_type &) A const version of the data pointed | ||
448 | * to by (k). | ||
449 | */ | ||
450 | virtual const value &get( key k ) const | ||
307 | { | 451 | { |
308 | _erase( nPos ); | 452 | uint32_t hash = __calcHashCode( k ); |
309 | onDelete(); | 453 | bool bFill; |
454 | uint32_t nPos = probe( hash, k, bFill ); | ||
455 | |||
456 | if( bFill ) | ||
457 | { | ||
458 | return aValues[nPos]; | ||
459 | } | ||
460 | else | ||
461 | { | ||
462 | throw HashException( | ||
463 | excodeNotFilled, | ||
464 | "No data assosiated with that key." | ||
465 | ); | ||
466 | } | ||
310 | } | 467 | } |
311 | } | ||
312 | 468 | ||
313 | struct iterator; | 469 | /** |
314 | virtual void erase( struct iterator &i ) | 470 | * Does the hash table contain an item under key (k). |
315 | { | 471 | *@param k (key_type) The key to check. |
316 | if( this != &i.hsh ) | 472 | *@returns (bool) Whether there was an item in the hash under key (k). |
317 | throw HashException("This iterator didn't come from this Hash."); | 473 | */ |
318 | if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) | 474 | virtual bool has( key k ) |
319 | { | 475 | { |
320 | _erase( i.nPos ); | 476 | bool bFill; |
321 | onDelete(); | 477 | probe( __calcHashCode( k ), k, bFill, false ); |
478 | |||
479 | return bFill; | ||
322 | } | 480 | } |
323 | } | ||
324 | 481 | ||
325 | virtual void clear() | 482 | /** |
326 | { | 483 | * Iteration structure for iterating through the hash. |
327 | for( uint32_t j = 0; j < nCapacity; j++ ) | 484 | */ |
485 | typedef struct iterator | ||
328 | { | 486 | { |
329 | if( isFilled( j ) ) | 487 | friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>; |
330 | if( !isDeleted( j ) ) | 488 | private: |
489 | iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh ) : | ||
490 | hsh( hsh ), | ||
491 | nPos( 0 ), | ||
492 | bFinished( false ) | ||
493 | { | ||
494 | nPos = hsh.getFirstPos( bFinished ); | ||
495 | } | ||
496 | |||
497 | iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh, bool bDone ) : | ||
498 | hsh( hsh ), | ||
499 | nPos( 0 ), | ||
500 | bFinished( bDone ) | ||
501 | { | ||
502 | } | ||
503 | |||
504 | Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh; | ||
505 | uint32_t nPos; | ||
506 | bool bFinished; | ||
507 | |||
508 | public: | ||
509 | /** | ||
510 | * Iterator incrementation operator. Move the iterator forward. | ||
511 | */ | ||
512 | iterator operator++( int ) | ||
513 | { | ||
514 | if( bFinished == false ) | ||
515 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
516 | |||
517 | return *this; | ||
518 | } | ||
519 | |||
520 | /** | ||
521 | * Iterator incrementation operator. Move the iterator forward. | ||
522 | */ | ||
523 | iterator operator++() | ||
524 | { | ||
525 | if( bFinished == false ) | ||
526 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
527 | |||
528 | return *this; | ||
529 | } | ||
530 | |||
531 | /** | ||
532 | * Iterator equality comparison operator. Iterators the same? | ||
533 | */ | ||
534 | bool operator==( const iterator &oth ) | ||
535 | { | ||
536 | if( bFinished != oth.bFinished ) | ||
537 | return false; | ||
538 | if( bFinished == true ) | ||
331 | { | 539 | { |
332 | va.destroy( &aValues[j] ); | 540 | return true; |
333 | ka.destroy( &aKeys[j] ); | ||
334 | onDelete(); | ||
335 | } | 541 | } |
336 | } | 542 | else |
337 | 543 | { | |
338 | clearBits(); | 544 | if( oth.nPos == nPos ) |
339 | } | 545 | return true; |
546 | return false; | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /** | ||
551 | * Iterator not equality comparison operator. Not the same? | ||
552 | */ | ||
553 | bool operator!=( const iterator &oth ) | ||
554 | { | ||
555 | return !(*this == oth ); | ||
556 | } | ||
340 | 557 | ||
341 | virtual value &get( key k ) | 558 | /** |
342 | { | 559 | * Iterator assignment operator. |
343 | uint32_t hash = __calcHashCode( k ); | 560 | */ |
344 | bool bFill; | 561 | iterator operator=( const iterator &oth ) |
345 | uint32_t nPos = probe( hash, k, bFill ); | 562 | { |
563 | if( &hsh != &oth.hsh ) | ||
564 | throw HashException( | ||
565 | "Cannot mix iterators from different hash objects."); | ||
566 | nPos = oth.nPos; | ||
567 | bFinished = oth.bFinished; | ||
568 | } | ||
346 | 569 | ||
347 | if( bFill ) | 570 | /** |
348 | { | 571 | * Iterator dereference operator... err.. get the value |
349 | return aValues[nPos]; | 572 | *@returns (value_type &) The value behind this iterator. |
350 | } | 573 | */ |
351 | else | 574 | value &operator *() |
575 | { | ||
576 | return hsh.getValueAtPos( nPos ); | ||
577 | } | ||
578 | |||
579 | /** | ||
580 | * Get the key behind this iterator. | ||
581 | *@returns (key_type &) The key behind this iterator. | ||
582 | */ | ||
583 | key &getKey() | ||
584 | { | ||
585 | return hsh.getKeyAtPos( nPos ); | ||
586 | } | ||
587 | |||
588 | /** | ||
589 | * Get the value behind this iterator. | ||
590 | *@returs (value_type &) The value behind this iterator. | ||
591 | */ | ||
592 | value &getValue() | ||
593 | { | ||
594 | return hsh.getValueAtPos( nPos ); | ||
595 | } | ||
596 | }; | ||
597 | |||
598 | /** | ||
599 | * Iteration structure for iterating through the hash (const). | ||
600 | */ | ||
601 | typedef struct const_iterator | ||
352 | { | 602 | { |
353 | throw HashException( | 603 | friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>; |
354 | excodeNotFilled, | 604 | private: |
355 | "No data assosiated with that key." | 605 | const_iterator( const Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh ) : |
356 | ); | 606 | hsh( hsh ), |
357 | } | 607 | nPos( 0 ), |
358 | } | 608 | bFinished( false ) |
609 | { | ||
610 | nPos = hsh.getFirstPos( bFinished ); | ||
611 | } | ||
612 | |||
613 | const_iterator( const Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh, bool bDone ) : | ||
614 | hsh( hsh ), | ||
615 | nPos( 0 ), | ||
616 | bFinished( bDone ) | ||
617 | { | ||
618 | } | ||
359 | 619 | ||
360 | virtual bool has( key k ) | 620 | const Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh; |
361 | { | 621 | uint32_t nPos; |
362 | bool bFill; | 622 | bool bFinished; |
363 | probe( __calcHashCode( k ), k, bFill, false ); | ||
364 | 623 | ||
365 | return bFill; | 624 | public: |
366 | } | 625 | /** |
626 | * Iterator incrementation operator. Move the iterator forward. | ||
627 | */ | ||
628 | const_iterator operator++( int ) | ||
629 | { | ||
630 | if( bFinished == false ) | ||
631 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
367 | 632 | ||
368 | typedef struct iterator | 633 | return *this; |
369 | { | 634 | } |
370 | friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>; | 635 | |
371 | private: | 636 | /** |
372 | iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh ) : | 637 | * Iterator incrementation operator. Move the iterator forward. |
373 | hsh( hsh ), | 638 | */ |
374 | nPos( 0 ), | 639 | const_iterator operator++() |
375 | bFinished( false ) | 640 | { |
641 | if( bFinished == false ) | ||
642 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
643 | |||
644 | return *this; | ||
645 | } | ||
646 | |||
647 | /** | ||
648 | * Iterator equality comparison operator. Iterators the same? | ||
649 | */ | ||
650 | bool operator==( const const_iterator &oth ) | ||
651 | { | ||
652 | if( bFinished != oth.bFinished ) | ||
653 | return false; | ||
654 | if( bFinished == true ) | ||
655 | { | ||
656 | return true; | ||
657 | } | ||
658 | else | ||
659 | { | ||
660 | if( oth.nPos == nPos ) | ||
661 | return true; | ||
662 | return false; | ||
663 | } | ||
664 | } | ||
665 | |||
666 | /** | ||
667 | * Iterator not equality comparison operator. Not the same? | ||
668 | */ | ||
669 | bool operator!=( const const_iterator &oth ) | ||
670 | { | ||
671 | return !(*this == oth ); | ||
672 | } | ||
673 | |||
674 | /** | ||
675 | * Iterator assignment operator. | ||
676 | */ | ||
677 | const_iterator operator=( const const_iterator &oth ) | ||
678 | { | ||
679 | if( &hsh != &oth.hsh ) | ||
680 | throw HashException( | ||
681 | "Cannot mix iterators from different hash objects."); | ||
682 | nPos = oth.nPos; | ||
683 | bFinished = oth.bFinished; | ||
684 | } | ||
685 | |||
686 | /** | ||
687 | * Iterator dereference operator... err.. get the value | ||
688 | *@returns (value_type &) The value behind this iterator. | ||
689 | */ | ||
690 | const value &operator *() const | ||
691 | { | ||
692 | return hsh.getValueAtPos( nPos ); | ||
693 | } | ||
694 | |||
695 | /** | ||
696 | * Get the key behind this iterator. | ||
697 | *@returns (key_type &) The key behind this iterator. | ||
698 | */ | ||
699 | const key &getKey() const | ||
700 | { | ||
701 | return hsh.getKeyAtPos( nPos ); | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * Get the value behind this iterator. | ||
706 | *@returs (value_type &) The value behind this iterator. | ||
707 | */ | ||
708 | const value &getValue() const | ||
709 | { | ||
710 | return hsh.getValueAtPos( nPos ); | ||
711 | } | ||
712 | }; | ||
713 | |||
714 | /** | ||
715 | * Get an iterator pointing to the first item in the hash table. | ||
716 | *@returns (iterator) An iterator pointing to the first item in the | ||
717 | * hash table. | ||
718 | */ | ||
719 | iterator begin() | ||
376 | { | 720 | { |
377 | nPos = hsh.getFirstPos( bFinished ); | 721 | return iterator( *this ); |
378 | } | 722 | } |
379 | 723 | ||
380 | iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh, bool bDone ) : | 724 | const_iterator begin() const |
381 | hsh( hsh ), | ||
382 | nPos( 0 ), | ||
383 | bFinished( bDone ) | ||
384 | { | 725 | { |
726 | return const_iterator( *this ); | ||
385 | } | 727 | } |
386 | 728 | ||
387 | Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh; | 729 | /** |
388 | uint32_t nPos; | 730 | * Get an iterator pointing to a point just past the last item in the |
389 | bool bFinished; | 731 | * hash table. |
390 | 732 | *@returns (iterator) An iterator pointing to a point just past the | |
391 | public: | 733 | * last item in the hash table. |
392 | iterator operator++( int ) | 734 | */ |
735 | iterator end() | ||
393 | { | 736 | { |
394 | if( bFinished == false ) | 737 | return iterator( *this, true ); |
395 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
396 | |||
397 | return *this; | ||
398 | } | 738 | } |
399 | 739 | ||
400 | iterator operator++() | 740 | const_iterator end() const |
401 | { | 741 | { |
402 | if( bFinished == false ) | 742 | return const_iterator( *this, true ); |
403 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
404 | |||
405 | return *this; | ||
406 | } | 743 | } |
407 | 744 | ||
408 | bool operator==( const iterator &oth ) | 745 | /** |
746 | * Get a list of all the keys in the hash table. | ||
747 | *@returns (std::list<key_type>) The list of keys in the hash table. | ||
748 | */ | ||
749 | Bu::List<key> getKeys() const | ||
409 | { | 750 | { |
410 | if( bFinished != oth.bFinished ) | 751 | Bu::List<key> lKeys; |
411 | return false; | 752 | |
412 | if( bFinished == true ) | 753 | for( uint32_t j = 0; j < nCapacity; j++ ) |
413 | { | 754 | { |
414 | return true; | 755 | if( isFilled( j ) ) |
756 | { | ||
757 | if( !isDeleted( j ) ) | ||
758 | { | ||
759 | lKeys.append( aKeys[j] ); | ||
760 | } | ||
761 | } | ||
415 | } | 762 | } |
416 | else | 763 | |
764 | return lKeys; | ||
765 | } | ||
766 | |||
767 | protected: | ||
768 | virtual void onInsert() {} | ||
769 | virtual void onUpdate() {} | ||
770 | virtual void onDelete() {} | ||
771 | virtual void onReHash() {} | ||
772 | |||
773 | virtual void clearBits() | ||
774 | { | ||
775 | for( uint32_t j = 0; j < nKeysSize; j++ ) | ||
417 | { | 776 | { |
418 | if( oth.nPos == nPos ) | 777 | bFilled[j] = bDeleted[j] = 0; |
419 | return true; | ||
420 | return false; | ||
421 | } | 778 | } |
422 | } | 779 | } |
423 | 780 | ||
424 | bool operator!=( const iterator &oth ) | 781 | virtual void fill( uint32_t loc, key &k, value &v, uint32_t hash ) |
425 | { | 782 | { |
426 | return !(*this == oth ); | 783 | bFilled[loc/32] |= (1<<(loc%32)); |
784 | va.construct( &aValues[loc], v ); | ||
785 | ka.construct( &aKeys[loc], k ); | ||
786 | aHashCodes[loc] = hash; | ||
787 | nFilled++; | ||
788 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
789 | // nFilled, nDeleted, nCapacity ); | ||
427 | } | 790 | } |
428 | 791 | ||
429 | iterator operator=( const iterator &oth ) | 792 | virtual void _erase( uint32_t loc ) |
430 | { | 793 | { |
431 | if( &hsh != &oth.hsh ) | 794 | bDeleted[loc/32] |= (1<<(loc%32)); |
432 | throw HashException( | 795 | va.destroy( &aValues[loc] ); |
433 | "Cannot mix iterators from different hash objects."); | 796 | ka.destroy( &aKeys[loc] ); |
434 | nPos = oth.nPos; | 797 | nDeleted++; |
435 | bFinished = oth.bFinished; | 798 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", |
799 | // nFilled, nDeleted, nCapacity ); | ||
436 | } | 800 | } |
437 | 801 | ||
438 | std::pair<key,value> operator *() | 802 | virtual std::pair<key,value> getAtPos( uint32_t nPos ) |
803 | { | ||
804 | return std::pair<key,value>(aKeys[nPos],aValues[nPos]); | ||
805 | } | ||
806 | |||
807 | virtual key &getKeyAtPos( uint32_t nPos ) | ||
439 | { | 808 | { |
440 | return hsh.getAtPos( nPos ); | 809 | return aKeys[nPos]; |
441 | } | 810 | } |
442 | 811 | ||
443 | key &getKey() | 812 | virtual const key &getKeyAtPos( uint32_t nPos ) const |
444 | { | 813 | { |
445 | return hsh.getKeyAtPos( nPos ); | 814 | return aKeys[nPos]; |
815 | } | ||
816 | |||
817 | virtual value &getValueAtPos( uint32_t nPos ) | ||
818 | { | ||
819 | return aValues[nPos]; | ||
820 | } | ||
821 | |||
822 | virtual const value &getValueAtPos( uint32_t nPos ) const | ||
823 | { | ||
824 | return aValues[nPos]; | ||
446 | } | 825 | } |
447 | 826 | ||
448 | value &getValue() | 827 | virtual uint32_t getFirstPos( bool &bFinished ) const |
449 | { | 828 | { |
450 | return hsh.getValueAtPos( nPos ); | 829 | for( uint32_t j = 0; j < nCapacity; j++ ) |
830 | { | ||
831 | if( isFilled( j ) ) | ||
832 | if( !isDeleted( j ) ) | ||
833 | return j; | ||
834 | } | ||
835 | |||
836 | bFinished = true; | ||
837 | return 0; | ||
451 | } | 838 | } |
452 | }; | ||
453 | 839 | ||
454 | iterator begin() | 840 | virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const |
455 | { | 841 | { |
456 | return iterator( *this ); | 842 | for( uint32_t j = nPos+1; j < nCapacity; j++ ) |
457 | } | 843 | { |
458 | 844 | if( isFilled( j ) ) | |
459 | iterator end() | 845 | if( !isDeleted( j ) ) |
460 | { | 846 | return j; |
461 | return iterator( *this, true ); | 847 | } |
462 | } | ||
463 | 848 | ||
464 | std::list<key> getKeys() | 849 | bFinished = true; |
465 | { | 850 | return 0; |
466 | std::list<key> lKeys; | 851 | } |
467 | 852 | ||
468 | for( uint32_t j = 0; j < nCapacity; j++ ) | 853 | uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) |
469 | { | 854 | { |
470 | if( isFilled( j ) ) | 855 | uint32_t nCur = hash%nCapacity; |
856 | |||
857 | // First we scan to see if the key is already there, abort if we | ||
858 | // run out of probing room, or we find a non-filled entry | ||
859 | for( int8_t j = 0; | ||
860 | isFilled( nCur ) && j < 32; | ||
861 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
862 | ) | ||
471 | { | 863 | { |
472 | if( !isDeleted( j ) ) | 864 | // Is this the same hash code we were looking for? |
865 | if( hash == aHashCodes[nCur] ) | ||
473 | { | 866 | { |
474 | lKeys.push_back( aKeys[j] ); | 867 | // Skip over deleted entries. Deleted entries are also filled, |
868 | // so we only have to do this check here. | ||
869 | if( isDeleted( nCur ) ) | ||
870 | continue; | ||
871 | |||
872 | // Is it really the same key? (for safety) | ||
873 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
874 | { | ||
875 | bFill = true; | ||
876 | return nCur; | ||
877 | } | ||
475 | } | 878 | } |
476 | } | 879 | } |
477 | } | ||
478 | 880 | ||
479 | return lKeys; | 881 | // This is our insurance, if the table is full, then go ahead and |
480 | } | 882 | // rehash, then try again. |
883 | if( isFilled( nCur ) && rehash == true ) | ||
884 | { | ||
885 | reHash( szCalc(getCapacity(), getFill(), getDeleted()) ); | ||
481 | 886 | ||
482 | protected: | 887 | // This is potentially dangerous, and could cause an infinite loop. |
483 | virtual void onInsert() {} | 888 | // Be careful writing probe, eh? |
484 | virtual void onUpdate() {} | 889 | return probe( hash, k, bFill ); |
485 | virtual void onDelete() {} | 890 | } |
486 | virtual void onReHash() {} | ||
487 | 891 | ||
488 | virtual void clearBits() | 892 | bFill = false; |
489 | { | 893 | return nCur; |
490 | for( uint32_t j = 0; j < nKeysSize; j++ ) | ||
491 | { | ||
492 | bFilled[j] = bDeleted[j] = 0; | ||
493 | } | 894 | } |
494 | } | 895 | |
495 | 896 | uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) const | |
496 | virtual void fill( uint32_t loc, key &k, value &v, uint32_t hash ) | ||
497 | { | ||
498 | bFilled[loc/32] |= (1<<(loc%32)); | ||
499 | va.construct( &aValues[loc], v ); | ||
500 | ka.construct( &aKeys[loc], k ); | ||
501 | aHashCodes[loc] = hash; | ||
502 | nFilled++; | ||
503 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
504 | // nFilled, nDeleted, nCapacity ); | ||
505 | } | ||
506 | |||
507 | virtual void _erase( uint32_t loc ) | ||
508 | { | ||
509 | bDeleted[loc/32] |= (1<<(loc%32)); | ||
510 | va.destroy( &aValues[loc] ); | ||
511 | ka.destroy( &aKeys[loc] ); | ||
512 | nDeleted++; | ||
513 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
514 | // nFilled, nDeleted, nCapacity ); | ||
515 | } | ||
516 | |||
517 | virtual std::pair<key,value> getAtPos( uint32_t nPos ) | ||
518 | { | ||
519 | return std::pair<key,value>(aKeys[nPos],aValues[nPos]); | ||
520 | } | ||
521 | |||
522 | virtual key &getKeyAtPos( uint32_t nPos ) | ||
523 | { | ||
524 | return aKeys[nPos]; | ||
525 | } | ||
526 | |||
527 | virtual value &getValueAtPos( uint32_t nPos ) | ||
528 | { | ||
529 | return aValues[nPos]; | ||
530 | } | ||
531 | |||
532 | virtual uint32_t getFirstPos( bool &bFinished ) | ||
533 | { | ||
534 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
535 | { | 897 | { |
536 | if( isFilled( j ) ) | 898 | uint32_t nCur = hash%nCapacity; |
537 | if( !isDeleted( j ) ) | 899 | |
538 | return j; | 900 | // First we scan to see if the key is already there, abort if we |
539 | } | 901 | // run out of probing room, or we find a non-filled entry |
902 | for( int8_t j = 0; | ||
903 | isFilled( nCur ) && j < 32; | ||
904 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
905 | ) | ||
906 | { | ||
907 | // Is this the same hash code we were looking for? | ||
908 | if( hash == aHashCodes[nCur] ) | ||
909 | { | ||
910 | // Skip over deleted entries. Deleted entries are also filled, | ||
911 | // so we only have to do this check here. | ||
912 | if( isDeleted( nCur ) ) | ||
913 | continue; | ||
914 | |||
915 | // Is it really the same key? (for safety) | ||
916 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
917 | { | ||
918 | bFill = true; | ||
919 | return nCur; | ||
920 | } | ||
921 | } | ||
922 | } | ||
540 | 923 | ||
541 | bFinished = true; | 924 | bFill = false; |
542 | return 0; | 925 | return nCur; |
543 | } | 926 | } |
544 | 927 | ||
545 | virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) | 928 | void reHash( uint32_t nNewSize ) |
546 | { | ||
547 | for( uint32_t j = nPos+1; j < nCapacity; j++ ) | ||
548 | { | 929 | { |
549 | if( isFilled( j ) ) | 930 | //printf("---REHASH---"); |
550 | if( !isDeleted( j ) ) | 931 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", |
551 | return j; | 932 | // nFilled, nDeleted, nCapacity ); |
552 | } | 933 | |
934 | // Save all the old data | ||
935 | uint32_t nOldCapacity = nCapacity; | ||
936 | uint32_t *bOldFilled = bFilled; | ||
937 | uint32_t *aOldHashCodes = aHashCodes; | ||
938 | uint32_t nOldKeysSize = nKeysSize; | ||
939 | uint32_t *bOldDeleted = bDeleted; | ||
940 | value *aOldValues = aValues; | ||
941 | key *aOldKeys = aKeys; | ||
942 | |||
943 | // Calculate new sizes | ||
944 | nCapacity = nNewSize; | ||
945 | nKeysSize = bitsToBytes( nCapacity ); | ||
946 | |||
947 | // Allocate new memory + prep | ||
948 | bFilled = ca.allocate( nKeysSize ); | ||
949 | bDeleted = ca.allocate( nKeysSize ); | ||
950 | clearBits(); | ||
553 | 951 | ||
554 | bFinished = true; | 952 | aHashCodes = ca.allocate( nCapacity ); |
555 | return 0; | 953 | aKeys = ka.allocate( nCapacity ); |
556 | } | 954 | aValues = va.allocate( nCapacity ); |
557 | 955 | ||
558 | uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) | 956 | nDeleted = nFilled = 0; |
559 | { | ||
560 | uint32_t nCur = hash%nCapacity; | ||
561 | 957 | ||
562 | // First we scan to see if the key is already there, abort if we | 958 | // Re-insert all of the old data (except deleted items) |
563 | // run out of probing room, or we find a non-filled entry | 959 | for( uint32_t j = 0; j < nOldCapacity; j++ ) |
564 | for( int8_t j = 0; | ||
565 | isFilled( nCur ) && j < 32; | ||
566 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
567 | ) | ||
568 | { | ||
569 | // Is this the same hash code we were looking for? | ||
570 | if( hash == aHashCodes[nCur] ) | ||
571 | { | 960 | { |
572 | // Skip over deleted entries. Deleted entries are also filled, | 961 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && |
573 | // so we only have to do this check here. | 962 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) |
574 | if( isDeleted( nCur ) ) | 963 | { |
575 | continue; | 964 | insert( aOldKeys[j], aOldValues[j] ); |
965 | } | ||
966 | } | ||
576 | 967 | ||
577 | // Is it really the same key? (for safety) | 968 | // Delete all of the old data |
578 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | 969 | for( uint32_t j = 0; j < nOldCapacity; j++ ) |
970 | { | ||
971 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 ) | ||
579 | { | 972 | { |
580 | bFill = true; | 973 | va.destroy( &aOldValues[j] ); |
581 | return nCur; | 974 | ka.destroy( &aOldKeys[j] ); |
582 | } | 975 | } |
583 | } | 976 | } |
977 | va.deallocate( aOldValues, nOldCapacity ); | ||
978 | ka.deallocate( aOldKeys, nOldCapacity ); | ||
979 | ca.deallocate( bOldFilled, nOldKeysSize ); | ||
980 | ca.deallocate( bOldDeleted, nOldKeysSize ); | ||
981 | ca.deallocate( aOldHashCodes, nOldCapacity ); | ||
584 | } | 982 | } |
585 | 983 | ||
586 | // This is our insurance, if the table is full, then go ahead and | 984 | virtual bool isFilled( uint32_t loc ) const |
587 | // rehash, then try again. | ||
588 | if( isFilled( nCur ) && rehash == true ) | ||
589 | { | 985 | { |
590 | reHash( szCalc(getCapacity(), getFill(), getDeleted()) ); | 986 | return (bFilled[loc/32]&(1<<(loc%32)))!=0; |
987 | } | ||
591 | 988 | ||
592 | // This is potentially dangerous, and could cause an infinite loop. | 989 | virtual bool isDeleted( uint32_t loc ) const |
593 | // Be careful writing probe, eh? | 990 | { |
594 | return probe( hash, k, bFill ); | 991 | return (bDeleted[loc/32]&(1<<(loc%32)))!=0; |
595 | } | 992 | } |
596 | 993 | ||
597 | bFill = false; | 994 | protected: |
598 | return nCur; | 995 | uint32_t nCapacity; |
599 | } | 996 | uint32_t nFilled; |
997 | uint32_t nDeleted; | ||
998 | uint32_t *bFilled; | ||
999 | uint32_t *bDeleted; | ||
1000 | uint32_t nKeysSize; | ||
1001 | key *aKeys; | ||
1002 | value *aValues; | ||
1003 | uint32_t *aHashCodes; | ||
1004 | valuealloc va; | ||
1005 | keyalloc ka; | ||
1006 | challoc ca; | ||
1007 | sizecalc szCalc; | ||
1008 | }; | ||
600 | 1009 | ||
601 | void reHash( uint32_t nNewSize ) | 1010 | template<> uint32_t __calcHashCode<int>( const int &k ); |
602 | { | 1011 | template<> bool __cmpHashKeys<int>( const int &a, const int &b ); |
603 | //printf("---REHASH---"); | ||
604 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
605 | // nFilled, nDeleted, nCapacity ); | ||
606 | |||
607 | // Save all the old data | ||
608 | uint32_t nOldCapacity = nCapacity; | ||
609 | uint32_t *bOldFilled = bFilled; | ||
610 | uint32_t *aOldHashCodes = aHashCodes; | ||
611 | uint32_t nOldKeysSize = nKeysSize; | ||
612 | uint32_t *bOldDeleted = bDeleted; | ||
613 | value *aOldValues = aValues; | ||
614 | key *aOldKeys = aKeys; | ||
615 | |||
616 | // Calculate new sizes | ||
617 | nCapacity = nNewSize; | ||
618 | nKeysSize = bitsToBytes( nCapacity ); | ||
619 | |||
620 | // Allocate new memory + prep | ||
621 | bFilled = ca.allocate( nKeysSize ); | ||
622 | bDeleted = ca.allocate( nKeysSize ); | ||
623 | clearBits(); | ||
624 | 1012 | ||
625 | aHashCodes = ca.allocate( nCapacity ); | 1013 | template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k ); |
626 | aKeys = ka.allocate( nCapacity ); | 1014 | template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b ); |
627 | aValues = va.allocate( nCapacity ); | ||
628 | 1015 | ||
629 | nDeleted = nFilled = 0; | 1016 | template<> uint32_t __calcHashCode<const char *>( const char * const &k ); |
1017 | template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b ); | ||
630 | 1018 | ||
631 | // Re-insert all of the old data (except deleted items) | 1019 | template<> uint32_t __calcHashCode<char *>( char * const &k ); |
632 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | 1020 | template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b ); |
633 | { | ||
634 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | ||
635 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
636 | { | ||
637 | insert( aOldKeys[j], aOldValues[j] ); | ||
638 | } | ||
639 | } | ||
640 | 1021 | ||
641 | // Delete all of the old data | 1022 | template<> uint32_t __calcHashCode<std::string>( const std::string &k ); |
642 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | 1023 | template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b ); |
1024 | |||
1025 | /* | ||
1026 | template<typename key, typename value> | ||
1027 | Archive &operator<<( Archive &ar, Hash<key,value> &h ) | ||
1028 | { | ||
1029 | ar << h.size(); | ||
1030 | for( typename Hash<key,value>::iterator i = h.begin(); i != h.end(); i++ ) | ||
643 | { | 1031 | { |
644 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | 1032 | std::pair<key,value> p = *i; |
645 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | 1033 | ar << p.first << p.second; |
646 | { | ||
647 | va.destroy( &aOldValues[j] ); | ||
648 | ka.destroy( &aOldKeys[j] ); | ||
649 | } | ||
650 | } | 1034 | } |
651 | va.deallocate( aOldValues, nOldCapacity ); | ||
652 | ka.deallocate( aOldKeys, nOldCapacity ); | ||
653 | ca.deallocate( bOldFilled, nOldKeysSize ); | ||
654 | ca.deallocate( bOldDeleted, nOldKeysSize ); | ||
655 | ca.deallocate( aOldHashCodes, nOldCapacity ); | ||
656 | } | ||
657 | 1035 | ||
658 | virtual bool isFilled( uint32_t loc ) const | 1036 | return ar; |
659 | { | ||
660 | return (bFilled[loc/32]&(1<<(loc%32)))!=0; | ||
661 | } | 1037 | } |
662 | 1038 | ||
663 | virtual bool isDeleted( uint32_t loc ) | 1039 | template<typename key, typename value> |
1040 | Archive &operator>>( Archive &ar, Hash<key,value> &h ) | ||
664 | { | 1041 | { |
665 | return (bDeleted[loc/32]&(1<<(loc%32)))!=0; | 1042 | h.clear(); |
666 | } | 1043 | uint32_t nSize; |
1044 | ar >> nSize; | ||
667 | 1045 | ||
668 | protected: | 1046 | for( uint32_t j = 0; j < nSize; j++ ) |
669 | uint32_t nCapacity; | 1047 | { |
670 | uint32_t nFilled; | 1048 | key k; value v; |
671 | uint32_t nDeleted; | 1049 | ar >> k >> v; |
672 | uint32_t *bFilled; | 1050 | h.insert( k, v ); |
673 | uint32_t *bDeleted; | 1051 | } |
674 | uint32_t nKeysSize; | ||
675 | key *aKeys; | ||
676 | value *aValues; | ||
677 | uint32_t *aHashCodes; | ||
678 | valuealloc va; | ||
679 | keyalloc ka; | ||
680 | challoc ca; | ||
681 | sizecalc szCalc; | ||
682 | }; | ||
683 | |||
684 | template<> uint32_t __calcHashCode<int>( const int &k ); | ||
685 | template<> bool __cmpHashKeys<int>( const int &a, const int &b ); | ||
686 | |||
687 | template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k ); | ||
688 | template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b ); | ||
689 | |||
690 | template<> uint32_t __calcHashCode<const char *>( const char * const &k ); | ||
691 | template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b ); | ||
692 | |||
693 | template<> uint32_t __calcHashCode<char *>( char * const &k ); | ||
694 | template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b ); | ||
695 | |||
696 | template<> uint32_t __calcHashCode<std::string>( const std::string &k ); | ||
697 | template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b ); | ||
698 | |||
699 | template<> uint32_t __calcHashCode<Hashable>( const Hashable &k ); | ||
700 | template<> bool __cmpHashKeys<Hashable>( const Hashable &a, const Hashable &b ); | ||
701 | |||
702 | template<typename key, typename value> | ||
703 | Serializer &operator<<( Serializer &ar, Hash<key,value> &h ) | ||
704 | { | ||
705 | ar << h.size(); | ||
706 | for( typename Hash<key,value>::iterator i = h.begin(); i != h.end(); i++ ) | ||
707 | { | ||
708 | std::pair<key,value> p = *i; | ||
709 | ar << p.first << p.second; | ||
710 | } | ||
711 | 1052 | ||
712 | return ar; | 1053 | return ar; |
713 | } | 1054 | }*/ |
714 | 1055 | ||
715 | template<typename key, typename value> | 1056 | /* |
716 | Serializer &operator>>( Serializer &ar, Hash<key,value> &h ) | 1057 | template<typename key, typename value> |
717 | { | 1058 | Serializer &operator&&( Serializer &ar, Hash<key,value> &h ) |
718 | h.clear(); | ||
719 | uint32_t nSize; | ||
720 | ar >> nSize; | ||
721 | |||
722 | for( uint32_t j = 0; j < nSize; j++ ) | ||
723 | { | 1059 | { |
724 | key k; value v; | 1060 | if( ar.isLoading() ) |
725 | ar >> k >> v; | 1061 | { |
726 | h.insert( k, v ); | 1062 | return ar >> h; |
727 | } | 1063 | } |
728 | 1064 | else | |
729 | return ar; | 1065 | { |
730 | } | 1066 | return ar << h; |
731 | 1067 | } | |
732 | template<typename key, typename value> | 1068 | }*/ |
733 | Serializer &operator&&( Serializer &ar, Hash<key,value> &h ) | ||
734 | { | ||
735 | if( ar.isLoading() ) | ||
736 | { | ||
737 | return ar >> h; | ||
738 | } | ||
739 | else | ||
740 | { | ||
741 | return ar << h; | ||
742 | } | ||
743 | } | 1069 | } |
744 | 1070 | ||
745 | #endif | 1071 | #endif |
diff --git a/src/hashable.cpp b/src/hashable.cpp deleted file mode 100644 index 8565956..0000000 --- a/src/hashable.cpp +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | #include "hashable.h" | ||
diff --git a/src/hashable.h b/src/hashable.h deleted file mode 100644 index 98643d5..0000000 --- a/src/hashable.h +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | #ifndef HASHABLE_H | ||
2 | #define HASHABLE_H | ||
3 | |||
4 | class Hashable | ||
5 | { | ||
6 | public: | ||
7 | virtual ~Hashable() {}; | ||
8 | virtual unsigned long int getHashCode() = 0; | ||
9 | virtual bool compareForHash( Hashable &other ) = 0; | ||
10 | }; | ||
11 | |||
12 | #endif | ||
diff --git a/src/hashfunction.cpp b/src/hashfunction.cpp deleted file mode 100644 index 51f2259..0000000 --- a/src/hashfunction.cpp +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | #include "hashfunction.h" | ||
2 | |||
3 | HashFunction::HashFunction() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | HashFunction::~HashFunction() | ||
8 | { | ||
9 | } | ||
10 | |||
diff --git a/src/hashfunction.h b/src/hashfunction.h deleted file mode 100644 index cbcf70f..0000000 --- a/src/hashfunction.h +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | #ifndef HASH_FUNCTION | ||
2 | #define HASH_FUNCTION | ||
3 | |||
4 | /** This represents the shell of a hash function. It must be aggregated in | ||
5 | * order to be used. Please read about it's two functions for specificatins | ||
6 | * relating to what values will be passed to them and what they should return | ||
7 | * for creating your own hash functions. | ||
8 | *@author Mike Buland. | ||
9 | */ | ||
10 | class HashFunction | ||
11 | { | ||
12 | public: | ||
13 | /** | ||
14 | * Standard Constructor. | ||
15 | */ | ||
16 | HashFunction(); | ||
17 | |||
18 | /** | ||
19 | * Standard Deconstructor. | ||
20 | */ | ||
21 | virtual ~HashFunction(); | ||
22 | |||
23 | /** Hashes the value represnted by id. This must return a fairly unique | ||
24 | * number in the range of 0-2^32 (or whatever the size of an unsigned long | ||
25 | * is on your system) based on the id given. The faster the number changes | ||
26 | * the better in a general sence. The return value will be the index | ||
27 | * (after probing takes place) to the data assosiated with an id, so this | ||
28 | * function should always produce the same number for any given id. | ||
29 | *@param id The identifier to use to create a unique numerical identifier. | ||
30 | *@returns A mostly unique numerical identifier generated using the given | ||
31 | * id. | ||
32 | */ | ||
33 | virtual unsigned long int hash( const void *id ) = 0; | ||
34 | |||
35 | /** This function must compare two ids in the format that this hashfunction | ||
36 | * accepts. For example, if the hash function hashes strings it should | ||
37 | * probably { return strcmp( id1, id2 ) == 0 }. | ||
38 | *@param id1 One value to use in the comparison | ||
39 | *@param id2 Another value to use in the comparison | ||
40 | *@returns True if the two values match, otherwise false. | ||
41 | */ | ||
42 | virtual bool cmpIDs( const void *id1, const void *id2 ) = 0; | ||
43 | |||
44 | // virtual void *createPersistantID( const void *id ) = 0; | ||
45 | // virtual void destroyPersistantID( const void *id ) = 0; | ||
46 | }; | ||
47 | |||
48 | #endif | ||
diff --git a/src/hashfunctioncasestring.cpp b/src/hashfunctioncasestring.cpp deleted file mode 100644 index 6361f45..0000000 --- a/src/hashfunctioncasestring.cpp +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <string.h> | ||
3 | #include <ctype.h> | ||
4 | #include "hashfunctioncasestring.h" | ||
5 | |||
6 | HashFunctionCaseString::HashFunctionCaseString() | ||
7 | { | ||
8 | } | ||
9 | |||
10 | HashFunctionCaseString::~HashFunctionCaseString() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | unsigned long int HashFunctionCaseString::hash( const void *id ) | ||
15 | { | ||
16 | const char *str = (const char *)id; | ||
17 | unsigned long int nPos = 0; | ||
18 | for( int j = 0; str[j] != '\0'; j++ ) | ||
19 | { | ||
20 | nPos = tolower(str[j]) + (nPos << 6) + (nPos << 16) - nPos; | ||
21 | // nPos += nPos<<16|(((unsigned long int)tolower(str[j]))<<((j*7)%24)); | ||
22 | } | ||
23 | return nPos; | ||
24 | } | ||
25 | |||
26 | bool HashFunctionCaseString::cmpIDs( const void *id1, const void *id2 ) | ||
27 | { | ||
28 | const char *str1 = (const char *)id1; | ||
29 | const char *str2 = (const char *)id2; | ||
30 | |||
31 | int j; | ||
32 | for( j = 0; str1[j] != '\0' && str2[j] != '\0'; j++ ) | ||
33 | { | ||
34 | if( tolower(str1[j]) != tolower(str2[j]) ) | ||
35 | return false; | ||
36 | } | ||
37 | return (str1[j]==str2[j]); | ||
38 | } | ||
39 | |||
diff --git a/src/hashfunctioncasestring.h b/src/hashfunctioncasestring.h deleted file mode 100644 index 7816a1b..0000000 --- a/src/hashfunctioncasestring.h +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | #ifndef HASH_FUNCTION_CASE_STRING | ||
2 | #define HASH_FUNCTION_CASE_STRING | ||
3 | |||
4 | #include "hashfunction.h" | ||
5 | |||
6 | /** A hash function for string data. This hash function does strings, but is | ||
7 | * actually generalized to handle any binary stream of characters terminated | ||
8 | * by a null character. This is different than HashFunctionString in that | ||
9 | * this does comparisons without regaurd to case. | ||
10 | *@author Mike Buland. | ||
11 | */ | ||
12 | class HashFunctionCaseString : public HashFunction | ||
13 | { | ||
14 | public: | ||
15 | /** | ||
16 | * Standard Constructor. | ||
17 | */ | ||
18 | HashFunctionCaseString(); | ||
19 | |||
20 | /** | ||
21 | * Standard Deconstructor. | ||
22 | */ | ||
23 | virtual ~HashFunctionCaseString(); | ||
24 | unsigned long int hash( const void *id ); | ||
25 | bool cmpIDs( const void *id1, const void *id2 ); | ||
26 | }; | ||
27 | |||
28 | #endif | ||
diff --git a/src/hashfunctionint.cpp b/src/hashfunctionint.cpp deleted file mode 100644 index 4bd0feb..0000000 --- a/src/hashfunctionint.cpp +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | #include "hashfunctionint.h" | ||
2 | |||
3 | HashFunctionInt::HashFunctionInt() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | HashFunctionInt::~HashFunctionInt() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | unsigned long int HashFunctionInt::hash( const void *id ) | ||
12 | { | ||
13 | return (unsigned long)(id); | ||
14 | } | ||
15 | |||
16 | bool HashFunctionInt::cmpIDs( const void *id1, const void *id2 ) | ||
17 | { | ||
18 | return (unsigned long)(id1) == (unsigned long)(id2); | ||
19 | } | ||
20 | |||
diff --git a/src/hashfunctionint.h b/src/hashfunctionint.h deleted file mode 100644 index 0fbc764..0000000 --- a/src/hashfunctionint.h +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | #ifndef HASH_FUNCTION_INT | ||
2 | #define HASH_FUNCTION_INT | ||
3 | |||
4 | #include "hashfunction.h" | ||
5 | |||
6 | /** A hash function for integer data. Really, this does almost nothing except | ||
7 | * ensure we're dealing with positive indicies. | ||
8 | *@author Mike Buland. | ||
9 | */ | ||
10 | class HashFunctionInt : public HashFunction | ||
11 | { | ||
12 | public: | ||
13 | /** | ||
14 | * Standard Constructor. | ||
15 | */ | ||
16 | HashFunctionInt(); | ||
17 | |||
18 | /** | ||
19 | * Standard Deconstructor. | ||
20 | */ | ||
21 | virtual ~HashFunctionInt(); | ||
22 | unsigned long int hash( const void *id ); | ||
23 | bool cmpIDs( const void *id1, const void *id2 ); | ||
24 | }; | ||
25 | |||
26 | #endif | ||
diff --git a/src/hashfunctionstring.cpp b/src/hashfunctionstring.cpp deleted file mode 100644 index bd14643..0000000 --- a/src/hashfunctionstring.cpp +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | #include "hashfunctionstring.h" | ||
2 | #ifndef NULL | ||
3 | #define NULL ((void *) 0) | ||
4 | #endif | ||
5 | |||
6 | HashFunctionString::HashFunctionString() | ||
7 | { | ||
8 | } | ||
9 | |||
10 | HashFunctionString::~HashFunctionString() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | unsigned long int HashFunctionString::hash( const void *id ) | ||
15 | { | ||
16 | if (id == NULL) | ||
17 | { | ||
18 | return 0; | ||
19 | } | ||
20 | |||
21 | unsigned long int nPos = 0; | ||
22 | for( const char *s = (const char *)id; *s; s++ ) | ||
23 | { | ||
24 | nPos = *s + (nPos << 6) + (nPos << 16) - nPos; | ||
25 | } | ||
26 | return nPos; | ||
27 | } | ||
28 | |||
29 | bool HashFunctionString::cmpIDs( const void *id1, const void *id2 ) | ||
30 | { | ||
31 | if (id1 == NULL || id2 == NULL) | ||
32 | { | ||
33 | return false; | ||
34 | } | ||
35 | if (id1 == id2) | ||
36 | { | ||
37 | return true; | ||
38 | } | ||
39 | |||
40 | const char *str1 = (const char *)id1; | ||
41 | const char *str2 = (const char *)id2; | ||
42 | |||
43 | int j; | ||
44 | for( j = 0; str1[j] != '\0' && str2[j] != '\0'; j++ ) | ||
45 | { | ||
46 | if( str1[j] != str2[j] ) | ||
47 | return false; | ||
48 | } | ||
49 | return (str1[j]==str2[j]); | ||
50 | } | ||
51 | |||
diff --git a/src/hashfunctionstring.h b/src/hashfunctionstring.h deleted file mode 100644 index 7d2a1a6..0000000 --- a/src/hashfunctionstring.h +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | #ifndef HASH_FUNCTION_STRING | ||
2 | #define HASH_FUNCTION_STRING | ||
3 | |||
4 | #include "hashfunction.h" | ||
5 | |||
6 | /** A hash function for string data. This hash function does strings, but is | ||
7 | * actually generalized to handle any binary stream of characters terminated | ||
8 | * by a null character. | ||
9 | *@author Mike Buland. | ||
10 | */ | ||
11 | class HashFunctionString : public HashFunction | ||
12 | { | ||
13 | public: | ||
14 | /** | ||
15 | * Standard Constructor. | ||
16 | */ | ||
17 | HashFunctionString(); | ||
18 | |||
19 | /** | ||
20 | * Standard Deconstructor. | ||
21 | */ | ||
22 | virtual ~HashFunctionString(); | ||
23 | unsigned long int hash( const void *id ); | ||
24 | bool cmpIDs( const void *id1, const void *id2 ); | ||
25 | }; | ||
26 | |||
27 | #endif | ||
diff --git a/src/hashtable.cpp b/src/hashtable.cpp deleted file mode 100644 index dbcd964..0000000 --- a/src/hashtable.cpp +++ /dev/null | |||
@@ -1,424 +0,0 @@ | |||
1 | #include <string.h> | ||
2 | #include <stdio.h> | ||
3 | #include <math.h> | ||
4 | |||
5 | #include "hashtable.h" | ||
6 | |||
7 | HashTable::HashTable( HashFunction *hNewFunc, unsigned long int nInitSize, bool bAllowDupes ) | ||
8 | { | ||
9 | hFunc = hNewFunc; | ||
10 | nTableSize = nextPrime( nInitSize ); | ||
11 | aTable = new HashNode[nTableSize]; | ||
12 | //for( int j = 0; j < nTableSize; j++ ) if( aTable[j].id || aTable[j].data || aTable[j].bDeleted ) printf("Unclean entry\n"); | ||
13 | nSize = 0; | ||
14 | nFilled = 0; | ||
15 | this->bAllowDupes = bAllowDupes; | ||
16 | } | ||
17 | |||
18 | HashTable::~HashTable() | ||
19 | { | ||
20 | delete[] aTable; | ||
21 | delete hFunc; | ||
22 | } | ||
23 | |||
24 | void HashTable::set( int j, const void *newID, const void *newData ) | ||
25 | { | ||
26 | if( newData == NULL ) | ||
27 | { | ||
28 | printf("Inserting NULL data is indestinguishable from uninserted data!\n"); | ||
29 | } | ||
30 | aTable[j].id = newID; | ||
31 | aTable[j].data = newData; | ||
32 | } | ||
33 | |||
34 | void HashTable::clear() | ||
35 | { | ||
36 | memset( aTable, 0, sizeof(HashNode) * nTableSize ); | ||
37 | } | ||
38 | |||
39 | bool HashTable::isFilled( int j ) | ||
40 | { | ||
41 | return (aTable[j].id != NULL)||(aTable[j].bDeleted); | ||
42 | } | ||
43 | |||
44 | void HashTable::reHash( unsigned long int nNewSize ) | ||
45 | { | ||
46 | HashNode *aOldTable = aTable; | ||
47 | unsigned long int oldSize = nTableSize; | ||
48 | |||
49 | // If the table can still be used if we just get rid of deleted items, don't | ||
50 | // change the size of the table, otherwise, go ahead and use the number | ||
51 | // passed in. | ||
52 | if( nSize > nTableSize>>1 ) | ||
53 | { | ||
54 | nTableSize = nextPrime( nNewSize ); | ||
55 | } | ||
56 | |||
57 | aTable = newTable( nTableSize ); | ||
58 | //for( int j = 0; j < nTableSize; j++ ) if( aTable[j].id || aTable[j].data || aTable[j].bDeleted ) printf("Unclean entry\n"); | ||
59 | |||
60 | nSize = 0; | ||
61 | nFilled = 0; | ||
62 | |||
63 | for( unsigned long int j = 0; j < oldSize; j++ ) | ||
64 | { | ||
65 | if( aOldTable[j].id != NULL && aOldTable[j].bDeleted == false ) | ||
66 | { | ||
67 | insert( aOldTable[j].id, aOldTable[j].data ); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | delete[] aOldTable; | ||
72 | } | ||
73 | |||
74 | unsigned long int HashTable::probe( unsigned long int nStart, const void *id ) | ||
75 | { | ||
76 | int nHash = nStart; | ||
77 | nStart = nStart%nTableSize; | ||
78 | if( bAllowDupes == true ) | ||
79 | { | ||
80 | for( | ||
81 | unsigned long int j=0; | ||
82 | isFilled( nStart ) && j < 32; | ||
83 | nStart = (nStart+(1<<j))%nTableSize, j++ | ||
84 | ); | ||
85 | |||
86 | /** | ||
87 | * This is an ugly little hack. If the hash table is too full in allow- | ||
88 | * dups mode we have to fall back on a linear search, otherwise you can | ||
89 | * only get up to 32 entries with the same name. | ||
90 | */ | ||
91 | if( isFilled( nStart ) ) | ||
92 | { | ||
93 | unsigned long int nOldStart = nStart; | ||
94 | for( | ||
95 | nStart++; | ||
96 | isFilled( nStart ) && nStart != nOldStart; | ||
97 | nStart = (nStart+1)%nTableSize | ||
98 | ); | ||
99 | } | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | for( | ||
104 | unsigned long int j=0; | ||
105 | isFilled( nStart ) && j < 32; | ||
106 | nStart = (nStart+(1<<j))%nTableSize, j++ | ||
107 | ) | ||
108 | { | ||
109 | if( isFilled( nStart ) ) | ||
110 | { | ||
111 | if( hFunc->cmpIDs( aTable[nStart].id, id ) == true && | ||
112 | aTable[nStart].bDeleted == false ) | ||
113 | { | ||
114 | return nStart; | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | // This is our insurance, if the table is full, then go ahead and rehash, | ||
120 | // then try again. | ||
121 | if( isFilled( nStart ) ) | ||
122 | { | ||
123 | reHash( getCapacity()*2 ); | ||
124 | return probe( nHash, id ); | ||
125 | } | ||
126 | return nStart; | ||
127 | } | ||
128 | |||
129 | HashTable::HashNode *HashTable::newTable( unsigned long int nNewSize ) | ||
130 | { | ||
131 | return new HashNode[nNewSize]; | ||
132 | } | ||
133 | |||
134 | #ifdef HASH_DEBUG_VIS | ||
135 | void HashTable::printDebugLine( const char *exData ) | ||
136 | { | ||
137 | char *buf = new char[getCapacity()+3]; | ||
138 | int j; | ||
139 | buf[0] = '['; | ||
140 | for( j = 0; j < getCapacity(); j++ ) | ||
141 | { | ||
142 | buf[j+1] = (aTable[j].bDeleted)?('X'):((isFilled( j ))?('#'):('-')); | ||
143 | } | ||
144 | buf[j+1] = ']'; | ||
145 | buf[j+2] = '\0'; | ||
146 | printf("%s %s\n", buf, exData ); | ||
147 | delete[] buf; | ||
148 | } | ||
149 | #endif | ||
150 | |||
151 | bool HashTable::insert( const void *id, const void *data ) | ||
152 | { | ||
153 | unsigned long int nPos = probe( hFunc->hash( id ), id )%nTableSize; | ||
154 | |||
155 | if( bAllowDupes == true ) | ||
156 | { | ||
157 | if( aTable[nPos].id == NULL && aTable[nPos].bDeleted == false ) | ||
158 | { | ||
159 | set( nPos, id, data ); | ||
160 | #ifdef HASH_DEBUG_VIS | ||
161 | printDebugLine( (const char *)id ); | ||
162 | #endif | ||
163 | nSize++; | ||
164 | nFilled++; | ||
165 | return true; | ||
166 | } | ||
167 | else | ||
168 | { | ||
169 | return false; | ||
170 | } | ||
171 | } | ||
172 | else | ||
173 | { | ||
174 | if( aTable[nPos].id == NULL && aTable[nPos].bDeleted == false ) | ||
175 | { | ||
176 | set( nPos, id, data ); | ||
177 | #ifdef HASH_DEBUG_VIS | ||
178 | printDebugLine( (const char *)id ); | ||
179 | #endif | ||
180 | nSize++; | ||
181 | nFilled++; | ||
182 | return true; | ||
183 | } | ||
184 | else if( hFunc->cmpIDs( aTable[nPos].id, id ) == true ) | ||
185 | { | ||
186 | set( nPos, id, data ); | ||
187 | #ifdef HASH_DEBUG_VIS | ||
188 | printDebugLine( (const char *)id ); | ||
189 | #endif | ||
190 | return true; | ||
191 | } | ||
192 | else | ||
193 | { | ||
194 | return false; | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | |||
199 | const void *HashTable::get( const void *id, unsigned long int nSkip ) | ||
200 | { | ||
201 | unsigned long int nPos = hFunc->hash( id )%nTableSize; | ||
202 | |||
203 | for( unsigned long int j=0; j < 32; nPos = (nPos+(1<<j))%nTableSize, j++ ) | ||
204 | { | ||
205 | if( !isFilled( nPos ) ) return NULL; | ||
206 | if( aTable[nPos].bDeleted == false ) | ||
207 | { | ||
208 | if( hFunc->cmpIDs( id, aTable[nPos].id ) ) | ||
209 | { | ||
210 | if( nSkip == 0 ) | ||
211 | { | ||
212 | return aTable[nPos].data; | ||
213 | } | ||
214 | else | ||
215 | { | ||
216 | nSkip--; | ||
217 | } | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | if( bAllowDupes ) | ||
223 | { | ||
224 | unsigned long int nOldPos = nPos; | ||
225 | for( nPos++; nPos != nOldPos; nPos=(nPos+1)%nTableSize ) | ||
226 | { | ||
227 | if( !isFilled( nPos ) ) return NULL; | ||
228 | if( aTable[nPos].bDeleted == false ) | ||
229 | { | ||
230 | if( hFunc->cmpIDs( id, aTable[nPos].id ) ) | ||
231 | { | ||
232 | if( nSkip == 0 ) | ||
233 | { | ||
234 | return aTable[nPos].data; | ||
235 | } | ||
236 | else | ||
237 | { | ||
238 | nSkip--; | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | |||
245 | return NULL; | ||
246 | } | ||
247 | |||
248 | const void *HashTable::getKey( const void *id, unsigned long int nSkip ) | ||
249 | { | ||
250 | unsigned long int nPos = hFunc->hash( id )%nTableSize; | ||
251 | |||
252 | for( unsigned long int j=0; j < 32; nPos = (nPos+(1<<j))%nTableSize, j++ ) | ||
253 | { | ||
254 | if( !isFilled( nPos ) ) return NULL; | ||
255 | if( aTable[nPos].bDeleted == false ) | ||
256 | { | ||
257 | if( hFunc->cmpIDs( id, aTable[nPos].id ) ) | ||
258 | { | ||
259 | if( nSkip == 0 ) | ||
260 | { | ||
261 | return aTable[nPos].id; | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | nSkip--; | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | |||
271 | if( bAllowDupes ) | ||
272 | { | ||
273 | unsigned long int nOldPos = nPos; | ||
274 | for( nPos++; nPos != nOldPos; nPos=(nPos+1)%nTableSize ) | ||
275 | { | ||
276 | if( !isFilled( nPos ) ) return NULL; | ||
277 | if( aTable[nPos].bDeleted == false ) | ||
278 | { | ||
279 | if( hFunc->cmpIDs( id, aTable[nPos].id ) ) | ||
280 | { | ||
281 | if( nSkip == 0 ) | ||
282 | { | ||
283 | return aTable[nPos].id; | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | nSkip--; | ||
288 | } | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return NULL; | ||
295 | } | ||
296 | |||
297 | void *HashTable::getFirstItemPos() | ||
298 | { | ||
299 | HashPos *pos = new HashPos; | ||
300 | return pos; | ||
301 | } | ||
302 | |||
303 | const void *HashTable::getItemData( void *xPos ) | ||
304 | { | ||
305 | return aTable[((HashPos *)xPos)->nPos].data; | ||
306 | } | ||
307 | |||
308 | const void *HashTable::getItemID( void *xPos ) | ||
309 | { | ||
310 | return aTable[((HashPos *)xPos)->nPos].id; | ||
311 | } | ||
312 | |||
313 | void *HashTable::getNextItemPos( void *xPos ) | ||
314 | { | ||
315 | HashPos *pos = (HashPos *)xPos; | ||
316 | if( pos->bStarted == false ) | ||
317 | { | ||
318 | pos->bStarted = true; | ||
319 | pos->nPos = 0; | ||
320 | } | ||
321 | else | ||
322 | { | ||
323 | pos->nPos++; | ||
324 | } | ||
325 | if( pos->nPos < nTableSize ) | ||
326 | { | ||
327 | for( ; pos->nPos < nTableSize; pos->nPos++ ) | ||
328 | { | ||
329 | if( isFilled( pos->nPos ) && | ||
330 | aTable[pos->nPos].bDeleted == false ) | ||
331 | { | ||
332 | return xPos; | ||
333 | } | ||
334 | } | ||
335 | } | ||
336 | |||
337 | delete pos; | ||
338 | |||
339 | return NULL; | ||
340 | } | ||
341 | |||
342 | // Big-O sqrt(n) | ||
343 | // Change this to be erethpothynies table with a storage | ||
344 | // lookup later on. | ||
345 | bool HashTable::isPrime (int num) | ||
346 | { | ||
347 | if (num == 2) // the only even prime | ||
348 | return true; | ||
349 | else if (num % 2 == 0) // other even numbers are composite | ||
350 | return false; | ||
351 | else | ||
352 | { | ||
353 | //bool prime = true; | ||
354 | int divisor = 3; | ||
355 | int upperLimit = static_cast<int>(sqrt(num) + 1); | ||
356 | while (divisor <= upperLimit) | ||
357 | { | ||
358 | if (num % divisor == 0) | ||
359 | return false; | ||
360 | // prime = false; | ||
361 | divisor +=2; | ||
362 | } | ||
363 | return true; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | // Big-O n^(3/2) | ||
368 | int HashTable::nextPrime( int base ) | ||
369 | { | ||
370 | int nPrime; | ||
371 | for( nPrime = base; isPrime( nPrime ) == false; nPrime++ ); | ||
372 | return nPrime; | ||
373 | } | ||
374 | |||
375 | unsigned long int HashTable::getCapacity() | ||
376 | { | ||
377 | return nTableSize; | ||
378 | } | ||
379 | |||
380 | unsigned long int HashTable::getSize() | ||
381 | { | ||
382 | return nSize; | ||
383 | } | ||
384 | |||
385 | double HashTable::getLoad() | ||
386 | { | ||
387 | return (double)(nFilled)/(double)(nTableSize); | ||
388 | } | ||
389 | |||
390 | const void *HashTable::operator[](const void *id) | ||
391 | { | ||
392 | return get( id ); | ||
393 | } | ||
394 | |||
395 | bool HashTable::del( const void *id, int nSkip ) | ||
396 | { | ||
397 | unsigned long int nPos = hFunc->hash( id )%nTableSize; | ||
398 | |||
399 | for( unsigned long int j=0; j < 32; nPos = (nPos+(1<<j))%nTableSize, j++ ) | ||
400 | { | ||
401 | if( !isFilled( nPos ) ) return false; | ||
402 | //printf("0x%08X \"%s\" == 0x%08X \"%s\" (%d)\n", id, id, aTable[nPos].id, aTable[nPos].id, nPos ); | ||
403 | if( hFunc->cmpIDs( id, aTable[nPos].id ) && | ||
404 | aTable[nPos].bDeleted == false ) | ||
405 | { | ||
406 | if( nSkip == 0 ) | ||
407 | { | ||
408 | aTable[nPos].bDeleted = true; | ||
409 | nSize--; | ||
410 | #ifdef HASH_DEBUG_VIS | ||
411 | printDebugLine( (const char *)id ); | ||
412 | #endif | ||
413 | return true; | ||
414 | } | ||
415 | else | ||
416 | { | ||
417 | nSkip--; | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | |||
422 | return false; | ||
423 | } | ||
424 | |||
diff --git a/src/hashtable.h b/src/hashtable.h deleted file mode 100644 index 179b694..0000000 --- a/src/hashtable.h +++ /dev/null | |||
@@ -1,308 +0,0 @@ | |||
1 | /**\hashtable.h | ||
2 | * Describes the HashFunction, HashFunctionString, and HashTable classes. It | ||
3 | * was just easier to put them all in one set of files. | ||
4 | *@author Mike Buland | ||
5 | */ | ||
6 | |||
7 | #ifndef HASH_TABLE_H | ||
8 | #define HASH_TABLE_H | ||
9 | |||
10 | //Uncomment this line to see a cool text-mode visualization of what's going on | ||
11 | //#define HASH_DEBUG_VIS 1 | ||
12 | |||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | #include <ctype.h> | ||
16 | |||
17 | #include "hashfunction.h" | ||
18 | |||
19 | /** | ||
20 | * A simple yet flexable hash-table. This uses several tricks to help ensure | ||
21 | * that the table is always running at maximum efficiency. You no longer have | ||
22 | * to specify a "danger fill level" when more space is needed a rehash is | ||
23 | * automatically trigered. Deleting elements is fully supported, as well as | ||
24 | * duplicate elements. To work with and allow duplicates simple construct your | ||
25 | * HashTable the way you normally would, but when deleting or getting elements | ||
26 | * you can specify a skip value. This effectively allows you to treat elements | ||
27 | * with duplicate ID's as though they were in a zero-based array. The first | ||
28 | * element inserted with a given ID would be at skip zero, the next at skip 1 | ||
29 | * and so on. This allows you to quickly search for elements with duplicate | ||
30 | * names, just stop when you get a null for a skip number, i.e. | ||
31 | * <pre> | ||
32 | * for( int j = 0;; j++ ) | ||
33 | * { | ||
34 | * void *pData = hash.get( myID, j ); | ||
35 | * if( !pData ) break; | ||
36 | * // Do something interesting with pData | ||
37 | * } | ||
38 | * </pre> | ||
39 | * There are new features in this HashTable that also allow for memory saving | ||
40 | * when dealing with systems where many elements are being deleted from the | ||
41 | * table. In those cases the elements deleted cannot be simply deleted, instead | ||
42 | * they have to be marked as deleted and hidden from the user, but maintained in | ||
43 | * the table so that future hashing operations don't fail. When rehashing | ||
44 | * occurs all elements marked as deleted are quietly removed. In these cases, | ||
45 | * if the number of deleted items would free enough space in the table for the | ||
46 | * table to be used efficiently without resizing, it is left the same size and | ||
47 | * rehashing is performed effectively in place, allowing the deleted items to | ||
48 | * be removed. | ||
49 | * <br> | ||
50 | * For info on adding new hashing algorithms, please see the HashFunction class. | ||
51 | *@author Mike Buland | ||
52 | *@todo Fix probing for tables that allow duplicates, and delete an item, then | ||
53 | * insert an item with the same name. | ||
54 | */ | ||
55 | class HashTable | ||
56 | { | ||
57 | public: | ||
58 | /** Constructs a hash table. | ||
59 | *@param hNewFunc A pointer to a hashfunction class to use. If this is | ||
60 | * null the default general string type will be used. | ||
61 | *@param nInitSize The initial size of the hashtable. | ||
62 | *@param bAllowDupes Setting this value to true allows the system to | ||
63 | * insert more than one copy of any given key. This can be tricky, and | ||
64 | * will require you to use the nSkip parameter on the get function. | ||
65 | */ | ||
66 | HashTable( HashFunction *hNewFunc, unsigned long int nInitSize, bool bAllowDupes=false ); | ||
67 | |||
68 | /** | ||
69 | * Destroys the hashtable, cleaning up all internal storage, but not stored | ||
70 | * elements. Also deletes the HashFunction passed in in the constructor. | ||
71 | */ | ||
72 | virtual ~HashTable(); | ||
73 | |||
74 | /** Inserts an item into the hashtable. This function will trigger a | ||
75 | * rehash if adding another item would force the table's load factor over | ||
76 | * the danger level. | ||
77 | *@param id used to find the data later. | ||
78 | *@param data The data item to insert into the table with the identifier | ||
79 | * id | ||
80 | *@returns True if insertion was successfull, and false if it failed. | ||
81 | */ | ||
82 | bool insert( const void *id, const void *data ); | ||
83 | |||
84 | /** Gets an item in the hashtable based on the id of that item. If there | ||
85 | * is more than one item with the same id you can use the nSkip parameter | ||
86 | * to access all of them. | ||
87 | *@param id The id of the item you're trying to find. | ||
88 | *@param nSkip The number of items with that id to skip before returning | ||
89 | * with the requested item. | ||
90 | *@returns A pointer to the data stored at the given id. | ||
91 | */ | ||
92 | const void *get( const void *id, unsigned long int nSkip=0 ); | ||
93 | |||
94 | const void *getKey( const void *id, unsigned long int nSkip=0 ); | ||
95 | |||
96 | /** Gets the total capacity of the hashtable. This is actually the number | ||
97 | * of total positions available inside the hashtable at the moment. This | ||
98 | * will change when the hashtable's load exceeds the danger level. | ||
99 | * Please note that this is NOT the actual amount of space available. | ||
100 | * In reality you can only access about 45-50 percent of that space. | ||
101 | *@returns The total capacity. | ||
102 | */ | ||
103 | unsigned long int getCapacity(); | ||
104 | |||
105 | /** Gets the number of filled in items in the hash table. This is roughly | ||
106 | * equivelent to the getSize function assosiated with the Lists. | ||
107 | *@returns The number of filled in items in the hash table. | ||
108 | */ | ||
109 | unsigned long int getSize(); | ||
110 | |||
111 | /** Gets the load (percentage) of filled in items in the table. This is | ||
112 | * technically the size divided by the capacity, but is definately usefull | ||
113 | * since it's required to check if it's time to rehash. | ||
114 | *@returns The table load in the range 0.0 to 1.0 | ||
115 | */ | ||
116 | double getLoad(); | ||
117 | |||
118 | /** Sets up an xPos object for use indexing the items in the table. Call | ||
119 | * this first and follow the directions for getNextItemPos below to | ||
120 | * iterate through every item in the table, while avoiding the empty | ||
121 | * spaces. | ||
122 | *@returns A pointer to a xPos object telling the hashtable where to find | ||
123 | * the item you're looking at. | ||
124 | */ | ||
125 | void *getFirstItemPos(); | ||
126 | |||
127 | /** Get the item's data that is being pointed to by xPos. This is only | ||
128 | * valid after xPos was created using getFirstItemPos and getNextItemPos | ||
129 | * was called at least once. | ||
130 | *@param xPos supplied by getFirstItemPos. | ||
131 | *@returns The key value that was used to insert the data into the table. | ||
132 | */ | ||
133 | const void *getItemData( void *xPos ); | ||
134 | |||
135 | /** Get the item's ID that is being pointed to by xPos. This is only | ||
136 | * valid after xPos was created using getFirstItemPos and getNextItemPos | ||
137 | * was called at least once. | ||
138 | *@param xPos supplied by getFirstItemPos. | ||
139 | *@returns The key value that was used to insert the data into the table. | ||
140 | */ | ||
141 | const void *getItemID( void *xPos ); | ||
142 | |||
143 | /** Used for iterating through a hash table sequentially. This will | ||
144 | * update the xPos pointer to point to the next time, all ready to | ||
145 | * be accessed with getItemID and getItemData. This must be called at | ||
146 | * least once before xPos is meaningful, and will return a NULL when it | ||
147 | * has reached the last item. | ||
148 | *@param xPos This must be an object created by a call to the function | ||
149 | * getFirstItemPos, and is only meaningful to the internal routines. | ||
150 | * Aborting a call in the middle (not running to the end of the table) | ||
151 | * may result in a memory leak at the moment. | ||
152 | *@returns xPos if still iterating through the list, otherwise it will | ||
153 | * return NULL when the end has been reached and the xPos variable has | ||
154 | * been deleted. | ||
155 | */ | ||
156 | void *getNextItemPos( void *xPos ); | ||
157 | |||
158 | /** A helpful operator to make accessing items easier. Please note that | ||
159 | * this simply returns a pointer to the data stored internally, and cannot | ||
160 | * be used like the STL operator to store new data, use insert for that. | ||
161 | *@param id The identifier used to store the requested item. | ||
162 | *@returns The data value assosiated with the given id, or NULL if it | ||
163 | * wasn't found in the table. | ||
164 | */ | ||
165 | const void *operator[](const void *id); | ||
166 | |||
167 | /** | ||
168 | * Delete the specified item from the hashtable. This actually keeps the | ||
169 | * data and marks it deleted. For all intents and purposes to the user it | ||
170 | * is deleted, except that the space is still used until a rehash is forced. | ||
171 | * This means that in hashtables where elements are being inserted and | ||
172 | * deleted frequently you may run into a higher rate of expansion. | ||
173 | *@param id The ID to delete. | ||
174 | *@param nSkip The number of similar id's to skip before deleting in a | ||
175 | * hashtable that allows duplicates. | ||
176 | *@returns True if the element was found and deleted, false otherwise. | ||
177 | */ | ||
178 | bool del( const void *id, int nSkip=0 ); | ||
179 | |||
180 | /** | ||
181 | * Deletes every entry in the hash table. See the notes on del to see what | ||
182 | * this means, except that since no data is being kept, the entire table is | ||
183 | * just marked as usable space. | ||
184 | */ | ||
185 | void clear(); | ||
186 | |||
187 | private: | ||
188 | /** | ||
189 | * Contains info related to a position in the hashtable. Used for | ||
190 | * searching through hashtables one item at a time, in order. This class | ||
191 | * should never be created by anything but a HashTable, and should never | ||
192 | * be referenced directly. Instead the hashtable returns a void pointer, | ||
193 | * which is what should be passed back in next time you use a search | ||
194 | * function. Always finish a search, since the object is deleted at the | ||
195 | * end of the search. | ||
196 | *@author Mike Buland | ||
197 | */ | ||
198 | class HashPos | ||
199 | { | ||
200 | public: | ||
201 | /** Create a blank HashPos. */ | ||
202 | HashPos() { bStarted=false; nPos = 0; }; | ||
203 | /** Has the search been started? */ | ||
204 | bool bStarted; | ||
205 | /** The position (index) into the backend storage structure. */ | ||
206 | unsigned long int nPos; | ||
207 | }; | ||
208 | |||
209 | /** | ||
210 | * All data related to a single element in the hashtable. This should | ||
211 | * really only be used and manipulated by the HashTable itself. | ||
212 | *@author Mike Buland | ||
213 | */ | ||
214 | typedef struct HashNode | ||
215 | { | ||
216 | public: | ||
217 | /** Create a new, empty HashNode. */ | ||
218 | HashNode() { id = NULL; data = NULL; bDeleted = false; }; | ||
219 | /** A pointer to the original ID that was used to key the data. */ | ||
220 | const void *id; | ||
221 | /** A pointer to the data stored along with the above ID. */ | ||
222 | const void *data; | ||
223 | /** Weather or not this data should really...exist */ | ||
224 | bool bDeleted; | ||
225 | } HashNode; | ||
226 | |||
227 | private: | ||
228 | /** | ||
229 | * Just sets the values in the element to some friendly values. | ||
230 | *@param newID The new ID to store. | ||
231 | *@param newData The new Data to store. | ||
232 | */ | ||
233 | void set( int j, const void *newID, const void *newData ); | ||
234 | /** | ||
235 | * Tells you if the node is filled or not. | ||
236 | *@returns True=an ID has been stored here, False=no ID. | ||
237 | */ | ||
238 | bool isFilled( int j ); | ||
239 | /** | ||
240 | * This actually resizes, but since every resize requires a reHash to go | ||
241 | * along with it, that's the name. This actually creates a new buffer for | ||
242 | * all of the contained data and then pulls every old element that was in | ||
243 | * the old table out and performs the hashing placement calculations again. | ||
244 | * This function skips all data that was marked as deleted, so at this | ||
245 | * point it really will be. | ||
246 | *@param nNewSize The new size to set the table to while re-hashing. | ||
247 | *@returns True if the operation was successful, false otherwise. | ||
248 | */ | ||
249 | void reHash( unsigned long int nNewSize ); | ||
250 | |||
251 | /** | ||
252 | * Helper function to allocate a new table. Really just does the memory | ||
253 | * allocation. | ||
254 | *@param nNewSize The size of the table to generate. | ||
255 | *@returns A new, blank array of HashNode objects the size you specified. | ||
256 | */ | ||
257 | HashNode *newTable( unsigned long int nNewSize ); | ||
258 | |||
259 | /** | ||
260 | * This function is used once an actual hash code is obtained. nStart is | ||
261 | * the given hash code, which is then wrapped to the size of the table. If | ||
262 | * there is data at that location, tests are performed to see if it's the | ||
263 | * right one. If it is, then it is returned, otherwise a series of further | ||
264 | * tests based on a 2^n search pattern is performed. The position of the | ||
265 | * requested data in the back-end storage is returned if found, otherwise | ||
266 | * another less useful value is returned... | ||
267 | *@param nStart The initial hashcode of the ID testing for. | ||
268 | *@param id A pointer to the id that is being searched for. | ||
269 | *@returns The real location of the data requested. | ||
270 | */ | ||
271 | unsigned long int probe( unsigned long int nStart, const void *id ); | ||
272 | |||
273 | /** | ||
274 | * Simple helper function to determine if a number is prime or not. | ||
275 | * This function runs in sqrt(n) time. | ||
276 | *@param num Number to test for prime-hood. | ||
277 | *@returns True if the number is prime, false otherwise. | ||
278 | */ | ||
279 | bool isPrime( int num ); | ||
280 | |||
281 | /** | ||
282 | * Given any number, this function finds the first number after it that is | ||
283 | * prime. Since this number is a multiple internally it's rare that the | ||
284 | * starting number would be prime. | ||
285 | *@param base The number to start the prime search on. | ||
286 | *@returns The first prime after the number given. | ||
287 | */ | ||
288 | int nextPrime( int base ); | ||
289 | |||
290 | #ifdef HASH_DEBUG_VIS | ||
291 | void printDebugLine( const char *exData ); | ||
292 | #endif | ||
293 | |||
294 | /** A pointer to the HashFunction subclass instance to use. */ | ||
295 | HashFunction *hFunc; | ||
296 | /** The complete array of HashNode objects to store data in. */ | ||
297 | HashNode *aTable; | ||
298 | /** The actual size of the table, not how many elements are in it. */ | ||
299 | unsigned long int nTableSize; | ||
300 | /** The number of elements that are in the table. */ | ||
301 | unsigned long int nSize; | ||
302 | /** The number of elements that are unavailable now. */ | ||
303 | unsigned long int nFilled; | ||
304 | /** Allow duplicate ID's in the table. */ | ||
305 | bool bAllowDupes; | ||
306 | }; | ||
307 | |||
308 | #endif | ||
diff --git a/src/inprogress/xmldocument.cpp b/src/inprogress/xmldocument.cpp new file mode 100644 index 0000000..cb21826 --- /dev/null +++ b/src/inprogress/xmldocument.cpp | |||
@@ -0,0 +1,9 @@ | |||
1 | #include "xmldocument.h" | ||
2 | |||
3 | Bu::XmlDocument::XmlDocument() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::XmlDocument::~XmlDocument() | ||
8 | { | ||
9 | } | ||
diff --git a/src/inprogress/xmldocument.h b/src/inprogress/xmldocument.h new file mode 100644 index 0000000..e16e3ea --- /dev/null +++ b/src/inprogress/xmldocument.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef XML_DOCUMENT_H | ||
2 | #define XML_DOCUMENT_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | namespace Bu | ||
7 | { | ||
8 | /** | ||
9 | * | ||
10 | */ | ||
11 | class XmlDocument | ||
12 | { | ||
13 | public: | ||
14 | XmlDocument(); | ||
15 | virtual ~XmlDocument(); | ||
16 | |||
17 | private: | ||
18 | |||
19 | }; | ||
20 | } | ||
21 | |||
22 | #endif | ||
diff --git a/src/inprogress/xmlnode.cpp b/src/inprogress/xmlnode.cpp new file mode 100644 index 0000000..58ef5c5 --- /dev/null +++ b/src/inprogress/xmlnode.cpp | |||
@@ -0,0 +1,9 @@ | |||
1 | #include "xmlnode.h" | ||
2 | |||
3 | Bu::XmlNode::XmlNode() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::XmlNode::~XmlNode() | ||
8 | { | ||
9 | } | ||
diff --git a/src/inprogress/xmlnode.h b/src/inprogress/xmlnode.h new file mode 100644 index 0000000..cd9961a --- /dev/null +++ b/src/inprogress/xmlnode.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef XML_NODE_H | ||
2 | #define XML_NODE_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | namespace Bu | ||
7 | { | ||
8 | /** | ||
9 | * | ||
10 | */ | ||
11 | class XmlNode | ||
12 | { | ||
13 | public: | ||
14 | XmlNode(); | ||
15 | virtual ~XmlNode(); | ||
16 | |||
17 | private: | ||
18 | |||
19 | }; | ||
20 | } | ||
21 | |||
22 | #endif | ||
diff --git a/src/inprogress/xmlreader.cpp b/src/inprogress/xmlreader.cpp new file mode 100644 index 0000000..bd241cf --- /dev/null +++ b/src/inprogress/xmlreader.cpp | |||
@@ -0,0 +1,267 @@ | |||
1 | #include "xmlreader.h" | ||
2 | |||
3 | Bu::XmlReader::XmlReader( Bu::Stream &sIn ) : | ||
4 | sIn( sIn ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | Bu::XmlReader::~XmlReader() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | const char *Bu::XmlReader::lookahead( int nAmnt ) | ||
13 | { | ||
14 | if( sBuf.getSize() >= nAmnt ) | ||
15 | return sBuf.getStr(); | ||
16 | |||
17 | int nNew = nAmnt - sBuf.getSize(); | ||
18 | char *buf = new char[nNew]; | ||
19 | sIn.read( buf, nNew ); | ||
20 | sBuf.append( buf ); | ||
21 | |||
22 | return sBuf.getStr(); | ||
23 | } | ||
24 | |||
25 | void Bu::XmlReader::burn( int nAmnt ) | ||
26 | { | ||
27 | if( sBuf.getSize() < nAmnt ) | ||
28 | { | ||
29 | lookahead( nAmnt ); | ||
30 | } | ||
31 | |||
32 | //sBuf.remove( nAmnt ); | ||
33 | } | ||
34 | |||
35 | void Bu::XmlReader::checkString( const char *str, int nLen ) | ||
36 | { | ||
37 | if( !strncmp( str, lookahead( nLen ), nLen ) ) | ||
38 | { | ||
39 | burn( nLen ); | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | throw Bu::ExceptionBase("Expected string '%s'", str ); | ||
44 | } | ||
45 | |||
46 | Bu::XmlNode *Bu::XmlReader::read() | ||
47 | { | ||
48 | prolog(); | ||
49 | } | ||
50 | |||
51 | void Bu::XmlReader::prolog() | ||
52 | { | ||
53 | XMLDecl(); | ||
54 | Misc(); | ||
55 | } | ||
56 | |||
57 | void Bu::XmlReader::XMLDecl() | ||
58 | { | ||
59 | checkString("<?xml", 5 ); | ||
60 | S(); | ||
61 | VersionInfo(); | ||
62 | EncodingDecl(); | ||
63 | SDDecl(); | ||
64 | Sq(); | ||
65 | checkString("?>", 2 ); | ||
66 | } | ||
67 | |||
68 | void Bu::XmlReader::Misc() | ||
69 | { | ||
70 | for(;;) | ||
71 | { | ||
72 | S(); | ||
73 | if( !strncmp("<!--", lookahead( 4 ), 4 ) ) | ||
74 | { | ||
75 | Comment(); | ||
76 | } | ||
77 | else if( !strncmp("<?", lookahead( 2 ), 2 ) ) | ||
78 | { | ||
79 | PI(); | ||
80 | } | ||
81 | else | ||
82 | { | ||
83 | return; | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | |||
88 | void Bu::XmlReader::Comment() | ||
89 | { | ||
90 | checkString("<!--", 4 ); | ||
91 | for(;;) | ||
92 | { | ||
93 | unsigned char c = *lookahead(1); | ||
94 | if( c == '-' ) | ||
95 | { | ||
96 | if( lookahead(2)[1] == '-' ) | ||
97 | { | ||
98 | checkString("-->", 3 ); | ||
99 | return; | ||
100 | } | ||
101 | } | ||
102 | burn( 1 ); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | void Bu::XmlReader::PI() | ||
107 | { | ||
108 | checkString("<?", 2 ); | ||
109 | FString sName = Name(); | ||
110 | printf("PI: %s\n---\n", sName.getStr() ); | ||
111 | S(); | ||
112 | for(int j = 0;; j++ ) | ||
113 | { | ||
114 | if( !strncmp( "?>", lookahead(j+2)+j, 2 ) ) | ||
115 | { | ||
116 | burn( j+2 ); | ||
117 | return; | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | void Bu::XmlReader::S() | ||
123 | { | ||
124 | for( int j = 0;; j++ ) | ||
125 | { | ||
126 | char c = *lookahead( 1 ); | ||
127 | if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA ) | ||
128 | continue; | ||
129 | if( j == 0 ) | ||
130 | throw ExceptionBase("Expected whitespace."); | ||
131 | return; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | void Bu::XmlReader::Sq() | ||
136 | { | ||
137 | for(;;) | ||
138 | { | ||
139 | char c = *lookahead( 1 ); | ||
140 | if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA ) | ||
141 | continue; | ||
142 | return; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | void Bu::XmlReader::VersionInfo() | ||
147 | { | ||
148 | try | ||
149 | { | ||
150 | S(); | ||
151 | checkString("version", 7 ); | ||
152 | } | ||
153 | catch( ExceptionBase &e ) | ||
154 | { | ||
155 | return; | ||
156 | } | ||
157 | Eq(); | ||
158 | Bu::FString ver = AttValue(); | ||
159 | if( ver != "1.1" ) | ||
160 | throw ExceptionBase("Currently we only support xml version 1.1\n"); | ||
161 | } | ||
162 | |||
163 | void Bu::XmlReader::Eq() | ||
164 | { | ||
165 | Sq(); | ||
166 | checkString("=", 1 ); | ||
167 | Sq(); | ||
168 | } | ||
169 | |||
170 | void Bu::XmlReader::EncodingDecl() | ||
171 | { | ||
172 | S(); | ||
173 | try | ||
174 | { | ||
175 | checkString("encoding", 8 ); | ||
176 | } | ||
177 | catch( ExceptionBase &e ) | ||
178 | { | ||
179 | return; | ||
180 | } | ||
181 | |||
182 | Eq(); | ||
183 | AttValue(); | ||
184 | } | ||
185 | |||
186 | void Bu::XmlReader::SDDecl() | ||
187 | { | ||
188 | S(); | ||
189 | try | ||
190 | { | ||
191 | checkString("standalone", 10 ); | ||
192 | } | ||
193 | catch( ExceptionBase &e ) | ||
194 | { | ||
195 | return; | ||
196 | } | ||
197 | |||
198 | Eq(); | ||
199 | AttValue(); | ||
200 | } | ||
201 | |||
202 | Bu::FString Bu::XmlReader::AttValue() | ||
203 | { | ||
204 | char q = *lookahead(1); | ||
205 | if( q == '\"' ) | ||
206 | { | ||
207 | for( int j = 2;; j++ ) | ||
208 | { | ||
209 | if( lookahead(j)[j-1] == '\"' ) | ||
210 | { | ||
211 | Bu::FString ret( lookahead(j)+1, j-2 ); | ||
212 | burn( j ); | ||
213 | return ret; | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | else if( q == '\'' ) | ||
218 | { | ||
219 | for( int j = 2;; j++ ) | ||
220 | { | ||
221 | if( lookahead(j)[j-1] == '\'' ) | ||
222 | { | ||
223 | Bu::FString ret( lookahead(j)+1, j-2 ); | ||
224 | burn( j ); | ||
225 | return ret; | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | throw ExceptionBase("Excpected either \' or \".\n"); | ||
231 | } | ||
232 | |||
233 | Bu::FString Bu::XmlReader::Name() | ||
234 | { | ||
235 | unsigned char c = *lookahead( 1 ); | ||
236 | if( c != ':' && c != '_' && | ||
237 | (c < 'A' || c > 'Z') && | ||
238 | (c < 'a' || c > 'z') && | ||
239 | (c < 0xC0 || c > 0xD6 ) && | ||
240 | (c < 0xD8 || c > 0xF6 ) && | ||
241 | (c < 0xF8)) | ||
242 | { | ||
243 | throw ExceptionBase("Invalid entity name starting character."); | ||
244 | } | ||
245 | |||
246 | for( int j = 1;; j++ ) | ||
247 | { | ||
248 | unsigned char c = lookahead(j+1)[j]; | ||
249 | if( isS( c ) ) | ||
250 | { | ||
251 | FString ret( lookahead(j+1), j+1 ); | ||
252 | burn( j+1 ); | ||
253 | return ret; | ||
254 | } | ||
255 | if( c != ':' && c != '_' && c != '-' && c != '.' && c != 0xB7 && | ||
256 | (c < 'A' || c > 'Z') && | ||
257 | (c < 'a' || c > 'z') && | ||
258 | (c < '0' || c > '9') && | ||
259 | (c < 0xC0 || c > 0xD6 ) && | ||
260 | (c < 0xD8 || c > 0xF6 ) && | ||
261 | (c < 0xF8)) | ||
262 | { | ||
263 | throw ExceptionBase("Invalid character in name."); | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
diff --git a/src/inprogress/xmlreader.h b/src/inprogress/xmlreader.h new file mode 100644 index 0000000..708a386 --- /dev/null +++ b/src/inprogress/xmlreader.h | |||
@@ -0,0 +1,121 @@ | |||
1 | #ifndef XML_READER_H | ||
2 | #define XML_READER_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include "bu/stream.h" | ||
6 | #include "bu/fstring.h" | ||
7 | #include "bu/xmlnode.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | /** | ||
12 | * An Xml 1.1 reader. I've decided to write this, this time, based on the | ||
13 | * official W3C reccomendation, now included with the source code. I've | ||
14 | * named the productions in the parser states the same as in that document, | ||
15 | * which may make them easier to find, etc, although possibly slightly less | ||
16 | * optimized than writing my own reduced grammer. | ||
17 | * | ||
18 | * Below I will list differences between my parser and the official standard | ||
19 | * as I come up with them. | ||
20 | * - Encoding and Standalone headings are ignored for the moment. (4.3.3, | ||
21 | * 2.9) | ||
22 | * - The standalone heading attribute can have any standard whitespace | ||
23 | * before it (the specs say only spaces, no newlines). (2.9) | ||
24 | * - Since standalone is ignored, it is currently allowed to have any | ||
25 | * value (should be restricted to "yes" or "no"). (2.9) | ||
26 | * - Currently only UTF-8 / ascii are parsed. | ||
27 | * - [optional] The content of comments is thrown away. (2.5) | ||
28 | * - The content of processing instruction blocks is parsed properly, but | ||
29 | * thrown away. (2.6) | ||
30 | */ | ||
31 | class XmlReader | ||
32 | { | ||
33 | public: | ||
34 | XmlReader( Bu::Stream &sIn ); | ||
35 | virtual ~XmlReader(); | ||
36 | |||
37 | XmlNode *read(); | ||
38 | |||
39 | private: | ||
40 | Bu::Stream &sIn; | ||
41 | Bu::FString sBuf; | ||
42 | |||
43 | private: // Helpers | ||
44 | const char *lookahead( int nAmnt ); | ||
45 | void burn( int nAmnt ); | ||
46 | void checkString( const char *str, int nLen ); | ||
47 | |||
48 | private: // States | ||
49 | /** | ||
50 | * The headers, etc. | ||
51 | */ | ||
52 | void prolog(); | ||
53 | |||
54 | /** | ||
55 | * The xml decleration (version, encoding, etc). | ||
56 | */ | ||
57 | void XMLDecl(); | ||
58 | |||
59 | /** | ||
60 | * Misc things, Includes Comments and PIData (Processing Instructions). | ||
61 | */ | ||
62 | void Misc(); | ||
63 | |||
64 | /** | ||
65 | * Comments | ||
66 | */ | ||
67 | void Comment(); | ||
68 | |||
69 | /** | ||
70 | * Processing Instructions | ||
71 | */ | ||
72 | void PI(); | ||
73 | |||
74 | /** | ||
75 | * Whitespace eater. | ||
76 | */ | ||
77 | void S(); | ||
78 | |||
79 | /** | ||
80 | * Optional whitespace eater. | ||
81 | */ | ||
82 | void Sq(); | ||
83 | |||
84 | /** | ||
85 | * XML Version spec | ||
86 | */ | ||
87 | void VersionInfo(); | ||
88 | |||
89 | /** | ||
90 | * Your basic equals sign with surrounding whitespace. | ||
91 | */ | ||
92 | void Eq(); | ||
93 | |||
94 | /** | ||
95 | * Read in an attribute value. | ||
96 | */ | ||
97 | FString AttValue(); | ||
98 | |||
99 | /** | ||
100 | * Read in the name of something. | ||
101 | */ | ||
102 | FString Name(); | ||
103 | |||
104 | /** | ||
105 | * Encoding decleration in the header | ||
106 | */ | ||
107 | void EncodingDecl(); | ||
108 | |||
109 | /** | ||
110 | * Standalone decleration in the header | ||
111 | */ | ||
112 | void SDDecl(); | ||
113 | |||
114 | bool isS( unsigned char c ) | ||
115 | { | ||
116 | return ( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA ); | ||
117 | } | ||
118 | }; | ||
119 | } | ||
120 | |||
121 | #endif | ||
diff --git a/src/inprogress/xmlwriter.cpp b/src/inprogress/xmlwriter.cpp new file mode 100644 index 0000000..23a5175 --- /dev/null +++ b/src/inprogress/xmlwriter.cpp | |||
@@ -0,0 +1,9 @@ | |||
1 | #include "xmlwriter.h" | ||
2 | |||
3 | Bu::XmlWriter::XmlWriter() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::XmlWriter::~XmlWriter() | ||
8 | { | ||
9 | } | ||
diff --git a/src/inprogress/xmlwriter.h b/src/inprogress/xmlwriter.h new file mode 100644 index 0000000..796d6fb --- /dev/null +++ b/src/inprogress/xmlwriter.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef XML_WRITER_H | ||
2 | #define XML_WRITER_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | namespace Bu | ||
7 | { | ||
8 | /** | ||
9 | * | ||
10 | */ | ||
11 | class XmlWriter | ||
12 | { | ||
13 | public: | ||
14 | XmlWriter(); | ||
15 | virtual ~XmlWriter(); | ||
16 | |||
17 | private: | ||
18 | |||
19 | }; | ||
20 | } | ||
21 | |||
22 | #endif | ||
diff --git a/src/ito.cpp b/src/ito.cpp new file mode 100644 index 0000000..001ca06 --- /dev/null +++ b/src/ito.cpp | |||
@@ -0,0 +1,40 @@ | |||
1 | #include "ito.h" | ||
2 | |||
3 | Bu::Ito::Ito() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::Ito::~Ito() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | bool Bu::Ito::start() | ||
12 | { | ||
13 | nHandle = pthread_create( &ptHandle, NULL, threadRunner, this ); | ||
14 | |||
15 | return true; | ||
16 | } | ||
17 | |||
18 | bool Bu::Ito::stop() | ||
19 | { | ||
20 | pthread_exit( &ptHandle ); | ||
21 | |||
22 | return true; | ||
23 | } | ||
24 | |||
25 | void *Bu::Ito::threadRunner( void *pThread ) | ||
26 | { | ||
27 | return ((Ito *)pThread)->run(); | ||
28 | } | ||
29 | |||
30 | bool Bu::Ito::join() | ||
31 | { | ||
32 | pthread_join( ptHandle, NULL ); | ||
33 | return true; | ||
34 | } | ||
35 | |||
36 | void Bu::Ito::yield() | ||
37 | { | ||
38 | pthread_yield(); | ||
39 | } | ||
40 | |||
diff --git a/src/ito.h b/src/ito.h new file mode 100644 index 0000000..c062052 --- /dev/null +++ b/src/ito.h | |||
@@ -0,0 +1,98 @@ | |||
1 | #ifndef BU_ITO_H | ||
2 | #define BU_ITO_H | ||
3 | |||
4 | #include <pthread.h> | ||
5 | |||
6 | namespace Bu | ||
7 | { | ||
8 | /** | ||
9 | * Simple thread class. This wraps the basic pthread (posix threads) system in | ||
10 | * an object oriented sort of way. It allows you to create a class with | ||
11 | * standard member variables and callable functions that can be run in it's own | ||
12 | * thread, one per class instance. | ||
13 | *@author Mike Buland | ||
14 | */ | ||
15 | class Ito | ||
16 | { | ||
17 | public: | ||
18 | /** | ||
19 | * Construct an Ito thread. | ||
20 | */ | ||
21 | Ito(); | ||
22 | |||
23 | /** | ||
24 | * Destroy an Ito thread. | ||
25 | */ | ||
26 | virtual ~Ito(); | ||
27 | |||
28 | /** | ||
29 | * Begin thread execution. This will call the overridden run function, | ||
30 | * which will simply execute in it's own thread until the function exits, | ||
31 | * the thread is killed, or the thread is cancelled (optionally). The | ||
32 | * thread started in this manner has access to all of it's class variables, | ||
33 | * but be sure to protect possible multiple-access with ItoMutex objects. | ||
34 | *@returns True if starting the thread was successful. False if something | ||
35 | * went wrong and the thread has not started. | ||
36 | */ | ||
37 | bool start(); | ||
38 | |||
39 | /** | ||
40 | * Forcibly kill a thread. This is not generally considered a good thing to | ||
41 | * do, but in those rare cases you need it, it's invaluable. The problem | ||
42 | * with stopping (or killing) a thread is that it stops it the moment you | ||
43 | * call stop, no matter what it's doing. The object oriented approach to | ||
44 | * this will help clean up any class variables that were used, but anything | ||
45 | * not managed as a member variable will probably create a memory leak type | ||
46 | * of situation. Instead of stop, consider using cancel, which can be | ||
47 | * handled by the running thread in a graceful manner. | ||
48 | *@returns True if the thread was stopped, false otherwise. When this | ||
49 | * function returns the thread may not have stopped, to ensure that the | ||
50 | * thread has really stopped, call join. | ||
51 | */ | ||
52 | bool stop(); | ||
53 | |||
54 | /** | ||
55 | * The workhorse of the Ito class. This is the function that will run in | ||
56 | * the thread, when this function exits the thread dies and is cleaned up | ||
57 | * by the system. Make sure to read up on ItoMutex, ItoCondition, and | ||
58 | * cancel to see how to control and protect everything you do in a safe way | ||
59 | * within this function. | ||
60 | *@returns I'm not sure right now, but this is the posix standard form. | ||
61 | */ | ||
62 | virtual void *run()=0; | ||
63 | |||
64 | /** | ||
65 | * Join the thread in action. This function performs what is commonly | ||
66 | * called a thread join. That is that it effectively makes the calling | ||
67 | * thread an the Ito thread contained in the called object one in the same, | ||
68 | * and pauses the calling thread until the called thread exits. That is, | ||
69 | * when called from, say, your main(), mythread.join() will not return until | ||
70 | * the thread mythread has exited. This is very handy at the end of | ||
71 | * programs to ensure all of your data was cleaned up. | ||
72 | *@returns True if the thread was joined, false if the thread couldn't be | ||
73 | * joined, usually because it isn't running to begin with. | ||
74 | */ | ||
75 | bool join(); | ||
76 | |||
77 | private: | ||
78 | pthread_t ptHandle; /**< Internal handle to the posix thread. */ | ||
79 | int nHandle; /**< Numeric handle to the posix thread. */ | ||
80 | |||
81 | protected: | ||
82 | /** | ||
83 | * This is the hidden-heard of the thread system. While run is what the | ||
84 | * user gets to override, and everything said about it is true, this is | ||
85 | * the function that actually makes up the thread, it simply calls the | ||
86 | * run member function in an OO-friendly way. This is what allows us to | ||
87 | * use member variables from within the thread itself. | ||
88 | *@param Should always be this. | ||
89 | *@returns This is specified by posix, I'm not sure yet. | ||
90 | */ | ||
91 | static void *threadRunner( void *pThread ); | ||
92 | |||
93 | void yield(); | ||
94 | |||
95 | }; | ||
96 | } | ||
97 | |||
98 | #endif | ||
diff --git a/src/itoatom.h b/src/itoatom.h new file mode 100644 index 0000000..7fc9090 --- /dev/null +++ b/src/itoatom.h | |||
@@ -0,0 +1,56 @@ | |||
1 | #ifndef BU_ITO_QUEUE_H | ||
2 | #define BU_ITO_QUEUE_H | ||
3 | |||
4 | #include <pthread.h> | ||
5 | |||
6 | #include "itomutex.h" | ||
7 | #include "itocondition.h" | ||
8 | |||
9 | /** | ||
10 | * A thread-safe wrapper class. | ||
11 | *@author Mike Buland | ||
12 | */ | ||
13 | template <class T> | ||
14 | class ItoAtom | ||
15 | { | ||
16 | public: | ||
17 | /** | ||
18 | * Construct an empty queue. | ||
19 | */ | ||
20 | ItoAtom() | ||
21 | { | ||
22 | } | ||
23 | |||
24 | ItoAtom( const T &src ) : | ||
25 | data( src ) | ||
26 | { | ||
27 | } | ||
28 | |||
29 | ~ItoQueue() | ||
30 | { | ||
31 | } | ||
32 | |||
33 | T get() | ||
34 | { | ||
35 | mOperate.lock(); | ||
36 | mOperate.unlock(); | ||
37 | return data; | ||
38 | } | ||
39 | |||
40 | void set( const T &val ) | ||
41 | { | ||
42 | mOperate.lock(); | ||
43 | data = val; | ||
44 | cBlock.signal(); | ||
45 | mOperate.unlock(); | ||
46 | } | ||
47 | |||
48 | private: | ||
49 | Item *pStart; /**< The start of the queue, the next element to dequeue. */ | ||
50 | Item *pEnd; /**< The end of the queue, the last element to dequeue. */ | ||
51 | |||
52 | ItoMutex mOperate; /**< The master mutex, used on all operations. */ | ||
53 | ItoCondition cBlock; /**< The condition for blocking dequeues. */ | ||
54 | }; | ||
55 | |||
56 | #endif | ||
diff --git a/src/itocondition.cpp b/src/itocondition.cpp new file mode 100644 index 0000000..d8f5375 --- /dev/null +++ b/src/itocondition.cpp | |||
@@ -0,0 +1,42 @@ | |||
1 | #include <sys/time.h> | ||
2 | |||
3 | #include "itocondition.h" | ||
4 | |||
5 | Bu::ItoCondition::ItoCondition() | ||
6 | { | ||
7 | pthread_cond_init( &cond, NULL ); | ||
8 | } | ||
9 | |||
10 | Bu::ItoCondition::~ItoCondition() | ||
11 | { | ||
12 | pthread_cond_destroy( &cond ); | ||
13 | } | ||
14 | |||
15 | int Bu::ItoCondition::wait() | ||
16 | { | ||
17 | return pthread_cond_wait( &cond, &mutex ); | ||
18 | } | ||
19 | |||
20 | int Bu::ItoCondition::wait( int nSec, int nUSec ) | ||
21 | { | ||
22 | struct timeval now; | ||
23 | struct timespec timeout; | ||
24 | struct timezone tz; | ||
25 | |||
26 | gettimeofday( &now, &tz ); | ||
27 | timeout.tv_sec = now.tv_sec + nSec + ((now.tv_usec + nUSec)/1000000); | ||
28 | timeout.tv_nsec = ((now.tv_usec + nUSec)%1000000)*1000; | ||
29 | |||
30 | return pthread_cond_timedwait( &cond, &mutex, &timeout ); | ||
31 | } | ||
32 | |||
33 | int Bu::ItoCondition::signal() | ||
34 | { | ||
35 | return pthread_cond_signal( &cond ); | ||
36 | } | ||
37 | |||
38 | int Bu::ItoCondition::broadcast() | ||
39 | { | ||
40 | return pthread_cond_broadcast( &cond ); | ||
41 | } | ||
42 | |||
diff --git a/src/itocondition.h b/src/itocondition.h new file mode 100644 index 0000000..1793f81 --- /dev/null +++ b/src/itocondition.h | |||
@@ -0,0 +1,81 @@ | |||
1 | #ifndef BU_ITO_CONDITION_H | ||
2 | #define BU_ITO_CONDITION_H | ||
3 | |||
4 | #include <pthread.h> | ||
5 | |||
6 | #include "itomutex.h" | ||
7 | |||
8 | namespace Bu | ||
9 | { | ||
10 | /** | ||
11 | * Ito condition. This is a fairly simple condition mechanism. As you may | ||
12 | * notice this class inherits from the ItoMutex class, this is because all | ||
13 | * conditions must be within a locked block. The standard usage of a condition | ||
14 | * is to pause one thread, perhaps indefinately, until another thread signals | ||
15 | * that it is alright to procede. | ||
16 | * <br> | ||
17 | * Standard usage for the thread that wants to wait is as follows: | ||
18 | * <pre> | ||
19 | * ItoCondition cond; | ||
20 | * ... // Perform setup and enter your run loop | ||
21 | * cond.lock(); | ||
22 | * while( !isFinished() ) // Could be anything you're waiting for | ||
23 | * cond.wait(); | ||
24 | * ... // Take care of what you have to. | ||
25 | * cond.unlock(); | ||
26 | * </pre> | ||
27 | * The usage for the triggering thread is much simpler, when it needs to tell | ||
28 | * the others that it's time to grab some data it calls either signal or | ||
29 | * broadcast. See both of those functions for the difference. | ||
30 | *@author Mike Buland | ||
31 | */ | ||
32 | class ItoCondition : public ItoMutex | ||
33 | { | ||
34 | public: | ||
35 | /** | ||
36 | * Create a condition. | ||
37 | */ | ||
38 | ItoCondition(); | ||
39 | |||
40 | /** | ||
41 | * Destroy a condition. | ||
42 | */ | ||
43 | ~ItoCondition(); | ||
44 | |||
45 | /** | ||
46 | * Wait forever, or until signalled. This has to be called from within a | ||
47 | * locked section, i.e. before calling this this object's lock function | ||
48 | * should be called. | ||
49 | */ | ||
50 | int wait(); | ||
51 | |||
52 | /** | ||
53 | * Wait for a maximum of nSec seconds and nUSec micro-seconds or until | ||
54 | * signalled. This is a little more friendly function if you want to | ||
55 | * perform other operations in the thrad loop that calls this function. | ||
56 | * Like the other wait function, this must be inside a locked section. | ||
57 | *@param nSec The seconds to wait. | ||
58 | *@param nUSec the micro-seconds to wait. | ||
59 | */ | ||
60 | int wait( int nSec, int nUSec ); | ||
61 | |||
62 | /** | ||
63 | * Notify the next thread waiting on this condition that they can go ahead. | ||
64 | * This only signals one thread, the next one in the condition queue, that | ||
65 | * it is safe to procede with whatever operation was being waited on. | ||
66 | */ | ||
67 | int signal(); | ||
68 | |||
69 | /** | ||
70 | * Notify all threads waiting on this condition that they can go ahead now. | ||
71 | * This function is slower than signal, but more effective in certain | ||
72 | * situations where you may not know how many threads should be activated. | ||
73 | */ | ||
74 | int broadcast(); | ||
75 | |||
76 | private: | ||
77 | pthread_cond_t cond; /**< Internal condition reference. */ | ||
78 | }; | ||
79 | } | ||
80 | |||
81 | #endif | ||
diff --git a/src/itomutex.cpp b/src/itomutex.cpp new file mode 100644 index 0000000..dc51af9 --- /dev/null +++ b/src/itomutex.cpp | |||
@@ -0,0 +1,27 @@ | |||
1 | #include "itomutex.h" | ||
2 | |||
3 | Bu::ItoMutex::ItoMutex() | ||
4 | { | ||
5 | pthread_mutex_init( &mutex, NULL ); | ||
6 | } | ||
7 | |||
8 | Bu::ItoMutex::~ItoMutex() | ||
9 | { | ||
10 | pthread_mutex_destroy( &mutex ); | ||
11 | } | ||
12 | |||
13 | int Bu::ItoMutex::lock() | ||
14 | { | ||
15 | return pthread_mutex_lock( &mutex ); | ||
16 | } | ||
17 | |||
18 | int Bu::ItoMutex::unlock() | ||
19 | { | ||
20 | return pthread_mutex_unlock( &mutex ); | ||
21 | } | ||
22 | |||
23 | int Bu::ItoMutex::trylock() | ||
24 | { | ||
25 | return pthread_mutex_trylock( &mutex ); | ||
26 | } | ||
27 | |||
diff --git a/src/itomutex.h b/src/itomutex.h new file mode 100644 index 0000000..9c9d205 --- /dev/null +++ b/src/itomutex.h | |||
@@ -0,0 +1,61 @@ | |||
1 | #ifndef BU_ITO_MUTEX_H | ||
2 | #define BU_ITO_MUTEX_H | ||
3 | |||
4 | #include <pthread.h> | ||
5 | |||
6 | namespace Bu | ||
7 | { | ||
8 | /** | ||
9 | * Simple mutex wrapper. Currently this doesn't do anything extra for you | ||
10 | * except keep all of the functionality together in an OO sorta' way and keep | ||
11 | * you from having to worry about cleaning up your mutexes properly, or initing | ||
12 | * them. | ||
13 | *@author Mike Buland | ||
14 | */ | ||
15 | class ItoMutex | ||
16 | { | ||
17 | public: | ||
18 | /** | ||
19 | * Create an unlocked mutex. | ||
20 | */ | ||
21 | ItoMutex(); | ||
22 | |||
23 | /** | ||
24 | * Destroy a mutex. This can only be done when a mutex is unlocked. | ||
25 | * Failure to unlock before destroying a mutex object could cause it to | ||
26 | * wait for the mutex to unlock, the odds of which are usually farily low | ||
27 | * at deconstruction time. | ||
28 | */ | ||
29 | ~ItoMutex(); | ||
30 | |||
31 | /** | ||
32 | * Lock the mutex. This causes all future calls to lock on this instance | ||
33 | * of mutex to block until the first thread that called mutex unlocks it. | ||
34 | * At that point the next thread that called lock will get a chance to go | ||
35 | * to work. Because of the nature of a mutex lock it is a very bad idea to | ||
36 | * do any kind of serious or rather time consuming computation within a | ||
37 | * locked section. This can cause thread-deadlock and your program may | ||
38 | * hang. | ||
39 | */ | ||
40 | int lock(); | ||
41 | |||
42 | /** | ||
43 | * Unlock the mutex. This allows the next thread that asked for a lock to | ||
44 | * lock the mutex and continue with execution. | ||
45 | */ | ||
46 | int unlock(); | ||
47 | |||
48 | /** | ||
49 | * Try to lock the mutex. This is the option to go with if you cannot avoid | ||
50 | * putting lengthy operations within a locked section. trylock will attempt | ||
51 | * to lock the mutex, if the mutex is already locked this function returns | ||
52 | * immediately with an error code. | ||
53 | */ | ||
54 | int trylock(); | ||
55 | |||
56 | protected: | ||
57 | pthread_mutex_t mutex; /**< The internal mutex reference. */ | ||
58 | }; | ||
59 | } | ||
60 | |||
61 | #endif | ||
diff --git a/src/itoqueue.h b/src/itoqueue.h new file mode 100644 index 0000000..75a2f27 --- /dev/null +++ b/src/itoqueue.h | |||
@@ -0,0 +1,231 @@ | |||
1 | #ifndef BU_ITO_QUEUE_H | ||
2 | #define BU_ITO_QUEUE_H | ||
3 | |||
4 | #include <pthread.h> | ||
5 | |||
6 | #include "itomutex.h" | ||
7 | #include "itocondition.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | /** | ||
12 | * A thread-safe queue class. This class is a very simple queue with some cool | ||
13 | * extra functionality for use with the Ito system. The main extra that it | ||
14 | * provides is the option to either dequeue without blocking, with infinite | ||
15 | * blocking, or with timed blocking, which will return a value if something is | ||
16 | * enqueued within the specified time limit, or NULL if the time limit is | ||
17 | * exceded. | ||
18 | *@author Mike Buland | ||
19 | */ | ||
20 | template <class T> | ||
21 | class ItoQueue | ||
22 | { | ||
23 | private: | ||
24 | /** | ||
25 | * Helper struct. Keeps track of linked-list items for the queue data. | ||
26 | */ | ||
27 | typedef struct Item | ||
28 | { | ||
29 | T pData; | ||
30 | Item *pNext; | ||
31 | } Item; | ||
32 | |||
33 | public: | ||
34 | /** | ||
35 | * Construct an empty queue. | ||
36 | */ | ||
37 | ItoQueue() : | ||
38 | pStart( NULL ), | ||
39 | pEnd( NULL ), | ||
40 | nSize( 0 ) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | /** | ||
45 | * Destroy the queue. This function will simply free all contained | ||
46 | * structures. If you stored pointers in the queue, this will lose the | ||
47 | * pointers without cleaning up the memory they pointed to. Make sure | ||
48 | * you're queue is empty before allowing it to be destroyed! | ||
49 | */ | ||
50 | ~ItoQueue() | ||
51 | { | ||
52 | Item *pCur = pStart; | ||
53 | while( pCur ) | ||
54 | { | ||
55 | Item *pTmp = pCur->pNext; | ||
56 | delete pCur; | ||
57 | pCur = pTmp; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * Enqueue a pieces of data. The new data will go at the end of the queue, | ||
63 | * and unless another piece of data is enqueued, will be the last piece of | ||
64 | * data to be dequeued. | ||
65 | *@param pData The data to enqueue. If this is not a primitive data type | ||
66 | * it's probably best to use a pointer type. | ||
67 | */ | ||
68 | void enqueue( T pData ) | ||
69 | { | ||
70 | mOperate.lock(); | ||
71 | |||
72 | if( pStart == NULL ) | ||
73 | { | ||
74 | pStart = pEnd = new Item; | ||
75 | pStart->pData = pData; | ||
76 | pStart->pNext = NULL; | ||
77 | nSize++; | ||
78 | } | ||
79 | else | ||
80 | { | ||
81 | pEnd->pNext = new Item; | ||
82 | pEnd = pEnd->pNext; | ||
83 | pEnd->pData = pData; | ||
84 | pEnd->pNext = NULL; | ||
85 | nSize++; | ||
86 | } | ||
87 | |||
88 | cBlock.signal(); | ||
89 | |||
90 | mOperate.unlock(); | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * Dequeue the first item from the queue. This function can operate in two | ||
95 | * different modes, blocking and non-blocking. In non-blocking mode it will | ||
96 | * return immediately weather there was data in the queue or not. If there | ||
97 | * was data it will remove it from the queue and return it to the caller. | ||
98 | * In blocking mode it will block forever wating for data to be enqueued. | ||
99 | * When data finally is enqueued this function will return immediately with | ||
100 | * the new data. The only way this function should ever return a null in | ||
101 | * blocking mode is if the calling thread was cancelled. It's probably a | ||
102 | * good idea to check for NULL return values even if you use blocking, just | ||
103 | * to be on the safe side. | ||
104 | *@param bBlock Set to true to enable blocking, leave as false to work in | ||
105 | * non-blocking mode. | ||
106 | *@returns The next piece of data in the queue, or NULL if no data was in | ||
107 | * the queue. | ||
108 | */ | ||
109 | T dequeue( bool bBlock=false ) | ||
110 | { | ||
111 | mOperate.lock(); | ||
112 | if( pStart == NULL ) | ||
113 | { | ||
114 | mOperate.unlock(); | ||
115 | |||
116 | if( bBlock ) | ||
117 | { | ||
118 | cBlock.lock(); | ||
119 | |||
120 | while( pStart == NULL ) | ||
121 | cBlock.wait(); | ||
122 | |||
123 | T tmp = dequeue( false ); | ||
124 | |||
125 | cBlock.unlock(); | ||
126 | return tmp; | ||
127 | |||
128 | } | ||
129 | |||
130 | return NULL; | ||
131 | } | ||
132 | else | ||
133 | { | ||
134 | T pTmp = pStart->pData; | ||
135 | Item *pDel = pStart; | ||
136 | pStart = pStart->pNext; | ||
137 | delete pDel; | ||
138 | nSize--; | ||
139 | |||
140 | mOperate.unlock(); | ||
141 | return pTmp; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | /** | ||
146 | * Operates just like the other dequeue function in blocking mode with one | ||
147 | * twist. This function will block for at most nSec seconds and nUSec | ||
148 | * micro-seconds. If the timer is up and no data is available, this will | ||
149 | * just return NULL. If data is enqueued before the timeout expires, it | ||
150 | * will dequeue and exit immediately. | ||
151 | *@param nSec The number of seconds to wait, max. | ||
152 | *@param nUSec The number of micro-seconds to wait, max. | ||
153 | *@returns The next piece of data in the queue, or NULL if the timeout was | ||
154 | * exceeded. | ||
155 | */ | ||
156 | T dequeue( int nSec, int nUSec ) | ||
157 | { | ||
158 | mOperate.lock(); | ||
159 | if( pStart == NULL ) | ||
160 | { | ||
161 | mOperate.unlock(); | ||
162 | |||
163 | cBlock.lock(); | ||
164 | |||
165 | cBlock.wait( nSec, nUSec ); | ||
166 | |||
167 | if( pStart == NULL ) | ||
168 | { | ||
169 | cBlock.unlock(); | ||
170 | return NULL; | ||
171 | } | ||
172 | |||
173 | mOperate.lock(); | ||
174 | T pTmp = pStart->pData; | ||
175 | Item *pDel = pStart; | ||
176 | pStart = pStart->pNext; | ||
177 | delete pDel; | ||
178 | nSize--; | ||
179 | mOperate.unlock(); | ||
180 | |||
181 | cBlock.unlock(); | ||
182 | return pTmp; | ||
183 | } | ||
184 | else | ||
185 | { | ||
186 | T pTmp = pStart->pData; | ||
187 | Item *pDel = pStart; | ||
188 | pStart = pStart->pNext; | ||
189 | delete pDel; | ||
190 | nSize--; | ||
191 | |||
192 | mOperate.unlock(); | ||
193 | return pTmp; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * Checks to see if the queue has data in it or not. Note that there is no | ||
199 | * function to determine the length of the queue. This data isn't kept | ||
200 | * track of. If you really need to know, fix this. | ||
201 | *@returns True if the queue is empty, false if it has data in it. | ||
202 | */ | ||
203 | bool isEmpty() | ||
204 | { | ||
205 | mOperate.lock(); | ||
206 | bool bEmpty = (pStart == NULL ); | ||
207 | mOperate.unlock(); | ||
208 | |||
209 | return bEmpty; | ||
210 | } | ||
211 | |||
212 | long getSize() | ||
213 | { | ||
214 | mOperate.lock(); | ||
215 | long nRet = nSize; | ||
216 | mOperate.unlock(); | ||
217 | |||
218 | return nRet; | ||
219 | } | ||
220 | |||
221 | private: | ||
222 | Item *pStart; /**< The start of the queue, the next element to dequeue. */ | ||
223 | Item *pEnd; /**< The end of the queue, the last element to dequeue. */ | ||
224 | long nSize; /**< The number of items in the queue. */ | ||
225 | |||
226 | ItoMutex mOperate; /**< The master mutex, used on all operations. */ | ||
227 | ItoCondition cBlock; /**< The condition for blocking dequeues. */ | ||
228 | }; | ||
229 | } | ||
230 | |||
231 | #endif | ||
diff --git a/src/linkmessage.cpp b/src/linkmessage.cpp index cf3df42..abe113c 100644 --- a/src/linkmessage.cpp +++ b/src/linkmessage.cpp | |||
@@ -1,12 +1,11 @@ | |||
1 | #include "linkmessage.h" | 1 | #include "bu/linkmessage.h" |
2 | #include <string.h> | ||
3 | 2 | ||
4 | LinkMessage::LinkMessage( int nNewMsg ) | 3 | Bu::LinkMessage::LinkMessage( int nNewMsg ) |
5 | { | 4 | { |
6 | nMsg = nNewMsg; | 5 | nMsg = nNewMsg; |
7 | } | 6 | } |
8 | 7 | ||
9 | LinkMessage::~LinkMessage() | 8 | Bu::LinkMessage::~LinkMessage() |
10 | { | 9 | { |
11 | } | 10 | } |
12 | 11 | ||
diff --git a/src/linkmessage.h b/src/linkmessage.h index 6cdfb2f..baa22a6 100644 --- a/src/linkmessage.h +++ b/src/linkmessage.h | |||
@@ -1,39 +1,42 @@ | |||
1 | /**\file linkmessage.h | 1 | /**\file linkmessage.h |
2 | */ | 2 | */ |
3 | 3 | ||
4 | #ifndef LINKMESSAGE_H | 4 | #ifndef BU_LINKMESSAGE_H |
5 | #define LINKMESSAGE_H | 5 | #define BU_LINKMESSAGE_H |
6 | 6 | ||
7 | /** | 7 | namespace Bu |
8 | * A message to be broadcast accross ProgramLinks in a ProgramChain. Generally | ||
9 | * one would make a subclass of this in order to transmit more useful | ||
10 | * information, but sometimes it isn't necesarry. | ||
11 | *@author Mike Buland | ||
12 | */ | ||
13 | class LinkMessage | ||
14 | { | 8 | { |
15 | public: | ||
16 | /** | 9 | /** |
17 | * Construct a blank LinkMessage. | 10 | * A message to be broadcast accross ProgramLinks in a ProgramChain. Generally |
11 | * one would make a subclass of this in order to transmit more useful | ||
12 | * information, but sometimes it isn't necesarry. | ||
13 | *@author Mike Buland | ||
18 | */ | 14 | */ |
19 | LinkMessage() {}; | 15 | class LinkMessage |
16 | { | ||
17 | public: | ||
18 | /** | ||
19 | * Construct a blank LinkMessage. | ||
20 | */ | ||
21 | LinkMessage() {}; | ||
20 | 22 | ||
21 | /** | 23 | /** |
22 | * Deconstruct a LinkMessage. | 24 | * Deconstruct a LinkMessage. |
23 | */ | 25 | */ |
24 | virtual ~LinkMessage(); | 26 | virtual ~LinkMessage(); |
25 | 27 | ||
26 | /** | 28 | /** |
27 | * Create a LinkMessage object with a specific message assosiated with it | 29 | * Create a LinkMessage object with a specific message assosiated with it |
28 | * to start with. | 30 | * to start with. |
29 | *@param nNewMsg The message to use in the Message object. | 31 | *@param nNewMsg The message to use in the Message object. |
30 | */ | 32 | */ |
31 | LinkMessage( int nNewMsg ); | 33 | LinkMessage( int nNewMsg ); |
32 | 34 | ||
33 | /** | 35 | /** |
34 | * The message contained in the Message object. | 36 | * The message contained in the Message object. |
35 | */ | 37 | */ |
36 | int nMsg; | 38 | int nMsg; |
37 | }; | 39 | }; |
40 | } | ||
38 | 41 | ||
39 | #endif | 42 | #endif |
diff --git a/src/list.cpp b/src/list.cpp index 18f1a66..abe92ad 100644 --- a/src/list.cpp +++ b/src/list.cpp | |||
@@ -1,10 +1,2 @@ | |||
1 | #include "list.h" | 1 | #include "bu/list.h" |
2 | |||
3 | List::List( ) | ||
4 | { | ||
5 | } | ||
6 | |||
7 | List::~List( ) | ||
8 | { | ||
9 | } | ||
10 | 2 | ||
@@ -1,101 +1,489 @@ | |||
1 | #ifndef LIST_H | 1 | #ifndef BU_LIST_H |
2 | #define LIST_H | 2 | #define BU_LIST_H |
3 | 3 | ||
4 | #include <memory> | ||
5 | #include "bu/exceptionbase.h" | ||
4 | 6 | ||
5 | /** The basic List class ADT. This, on it's own, does absolutely nothing, but | 7 | namespace Bu |
6 | * does define all standard interface functions to access a list. | ||
7 | *@author Mike Buland | ||
8 | */ | ||
9 | class List | ||
10 | { | 8 | { |
11 | public: | 9 | template<typename value> |
12 | /** | 10 | struct ListLink |
13 | * Construct a list. | 11 | { |
14 | */ | 12 | value *pValue; |
15 | List(); | 13 | ListLink *pNext; |
14 | ListLink *pPrev; | ||
15 | }; | ||
16 | 16 | ||
17 | /** | 17 | /** |
18 | * Desconstruct a list. | 18 | * Linked list template container. This class is similar to the stl list |
19 | * class except for a few minor changes. First, it doesn't mimic a stack or | ||
20 | * queue, use the Stack or Queue clasess for that. Second, when const, all | ||
21 | * members are only accessable const. Third, erasing a location does not | ||
22 | * invalidate the iterator, it simply points to the next valid location, or | ||
23 | * end() if there are no more. | ||
24 | * | ||
25 | *@param value (typename) The type of data to store in your list | ||
26 | *@param valuealloc (typename) Memory Allocator for your value type | ||
27 | *@param linkalloc (typename) Memory Allocator for the list links. | ||
19 | */ | 28 | */ |
20 | virtual ~List(); | 29 | template<typename value, typename valuealloc=std::allocator<value>, typename linkalloc=std::allocator<struct ListLink<value> > > |
21 | 30 | class List | |
22 | /** Gets the value at a specified index. | 31 | { |
23 | *@param nIndex The index of the item to return. | 32 | private: |
24 | *@returns The specified item, or NULL if the index was beyond the range | 33 | typedef struct ListLink<value> Link; |
25 | * of the list. | 34 | typedef class List<value, valuealloc, linkalloc> MyType; |
26 | *@author Mike Buland | ||
27 | */ | ||
28 | virtual void *getAt( int nIndex ) = 0; | ||
29 | |||
30 | /** Append the given data to the end of the list. This increases the | ||
31 | * size of the list by one. | ||
32 | *@param pData The data to append to the list. | ||
33 | *@author Mike Buland | ||
34 | */ | ||
35 | virtual void append( void *pData ) = 0; | ||
36 | |||
37 | /** Inserts an item at the specified position in the list. The | ||
38 | * new item takes the index that you specify, and all other items | ||
39 | * are moved up one position. The size of the list is increased by | ||
40 | * one. | ||
41 | *@param pData The value to insert into the list. | ||
42 | *@param nPos Where to insert the data into the list. | ||
43 | *@author Mike Buland | ||
44 | */ | ||
45 | virtual void insertBefore( void *pData, int nPos = 0 ) = 0; | ||
46 | |||
47 | /** Determines the size of the list, in elements. | ||
48 | *@returns The size of the list. | ||
49 | *@author Mike Buland | ||
50 | */ | ||
51 | virtual int getSize( ) = 0; | ||
52 | |||
53 | /** Determines if the list is empty or not. | ||
54 | *@returns True if the list is empty, or false if the list has | ||
55 | * data in it (if the size is greater than zero). | ||
56 | *@author Mike Buland | ||
57 | */ | ||
58 | virtual bool isEmpty( ) = 0; | ||
59 | |||
60 | /** Deletes an item at the specified index and moves all other | ||
61 | * values down one index. The size of the list is decreased by one. | ||
62 | *@param nIndex The index of the item to delete. | ||
63 | *@author Mike Buland | ||
64 | */ | ||
65 | virtual void deleteAt( int nIndex ) = 0; | ||
66 | |||
67 | /** Completely empties the list, and sets the effective size to | ||
68 | * zero. | ||
69 | *@author Mike Buland | ||
70 | */ | ||
71 | virtual void empty() = 0; | ||
72 | |||
73 | /** Sets the size of the list. This can be larger or smaller | ||
74 | * than what it was previously. If larger, new blank items will | ||
75 | * be added to the end of the list. If smaller than the old list | ||
76 | * items will be deleted from the end. | ||
77 | *@param nNewSize The new size of the list. | ||
78 | *@author Mike Buland | ||
79 | */ | ||
80 | virtual void setSize( int nNewSize ) = 0; | ||
81 | |||
82 | /** Sets a member at a specified location to a new value. | ||
83 | * If the member being set is outside of the range of the | ||
84 | * current list it should be expanded. | ||
85 | *@param nIndex The zero-based index of the item to change. | ||
86 | *@param pData The new value for that index. | ||
87 | *@author Mike Buland | ||
88 | */ | ||
89 | virtual void setAt( int nIndex, void *pData ) = 0; | ||
90 | |||
91 | /** Makes the List work like an array. Just say listObj[2] to get | ||
92 | * the third element. | ||
93 | *@param nIndex The index to access in the list. | ||
94 | *@returns A pointer to the data at element index. | ||
95 | *@author Mike Buland | ||
96 | */ | ||
97 | void *operator[]( int nIndex ) { return getAt( nIndex ); }; | ||
98 | }; | ||
99 | 35 | ||
100 | #endif | 36 | public: |
37 | List() : | ||
38 | pFirst( NULL ), | ||
39 | pLast( NULL ), | ||
40 | nSize( 0 ) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | List( const MyType &src ) : | ||
45 | pFirst( NULL ), | ||
46 | pLast( NULL ), | ||
47 | nSize( 0 ) | ||
48 | { | ||
49 | for( Link *pCur = src.pFirst; pCur; pCur = pCur->pNext ) | ||
50 | { | ||
51 | append( *pCur->pValue ); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | ~List() | ||
56 | { | ||
57 | clear(); | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * Assignment operator. | ||
62 | *@param src (const MyType &) The list to assign to your list. | ||
63 | */ | ||
64 | MyType &operator=( const MyType &src ) | ||
65 | { | ||
66 | clear(); | ||
67 | for( Link *pCur = src.pFirst; pCur; pCur = pCur->pNext ) | ||
68 | { | ||
69 | append( *pCur->pValue ); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * Clear the data from the list. | ||
75 | */ | ||
76 | void clear() | ||
77 | { | ||
78 | Link *pCur = pFirst; | ||
79 | for(;;) | ||
80 | { | ||
81 | if( pCur == NULL ) break; | ||
82 | va.destroy( pCur->pValue ); | ||
83 | va.deallocate( pCur->pValue, 1 ); | ||
84 | Link *pTmp = pCur->pNext; | ||
85 | la.destroy( pCur ); | ||
86 | la.deallocate( pCur, 1 ); | ||
87 | pCur = pTmp; | ||
88 | } | ||
89 | pFirst = pLast = NULL; | ||
90 | nSize = 0; | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * Append a value to the list. | ||
95 | *@param v (const value_type &) The value to append. | ||
96 | */ | ||
97 | void append( const value &v ) | ||
98 | { | ||
99 | Link *pNew = la.allocate( 1 ); | ||
100 | pNew->pValue = va.allocate( 1 ); | ||
101 | va.construct( pNew->pValue, v ); | ||
102 | nSize++; | ||
103 | if( pFirst == NULL ) | ||
104 | { | ||
105 | // Empty list | ||
106 | pFirst = pLast = pNew; | ||
107 | pNew->pNext = pNew->pPrev = NULL; | ||
108 | } | ||
109 | else | ||
110 | { | ||
111 | pNew->pNext = NULL; | ||
112 | pNew->pPrev = pLast; | ||
113 | pLast->pNext = pNew; | ||
114 | pLast = pNew; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * Prepend a value to the list. | ||
120 | *@param v (const value_type &) The value to prepend. | ||
121 | */ | ||
122 | void prepend( const value &v ) | ||
123 | { | ||
124 | Link *pNew = la.allocate( 1 ); | ||
125 | pNew->pValue = va.allocate( 1 ); | ||
126 | va.construct( pNew->pValue, v ); | ||
127 | nSize++; | ||
128 | if( pFirst == NULL ) | ||
129 | { | ||
130 | // Empty list | ||
131 | pFirst = pLast = pNew; | ||
132 | pNew->pNext = pNew->pPrev = NULL; | ||
133 | } | ||
134 | else | ||
135 | { | ||
136 | pNew->pNext = pFirst; | ||
137 | pNew->pPrev = NULL; | ||
138 | pFirst->pPrev = pNew; | ||
139 | pFirst = pNew; | ||
140 | } | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * An iterator to iterate through your list. | ||
145 | */ | ||
146 | typedef struct iterator | ||
147 | { | ||
148 | friend class List<value, valuealloc, linkalloc>; | ||
149 | private: | ||
150 | Link *pLink; | ||
151 | iterator() : | ||
152 | pLink( NULL ) | ||
153 | { | ||
154 | } | ||
155 | |||
156 | iterator( Link *pLink ) : | ||
157 | pLink( pLink ) | ||
158 | { | ||
159 | } | ||
160 | |||
161 | public: | ||
162 | /** | ||
163 | * Equals comparison operator. | ||
164 | *@param oth (const iterator &) The iterator to compare to. | ||
165 | *@returns (bool) Are they equal? | ||
166 | */ | ||
167 | bool operator==( const iterator &oth ) const | ||
168 | { | ||
169 | return ( pLink == oth.pLink ); | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * Equals comparison operator. | ||
174 | *@param pOth (const Link *) The link to compare to. | ||
175 | *@returns (bool) Are they equal? | ||
176 | */ | ||
177 | bool operator==( const Link *pOth ) const | ||
178 | { | ||
179 | return ( pLink == pOth ); | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * Not equals comparison operator. | ||
184 | *@param oth (const iterator &) The iterator to compare to. | ||
185 | *@returns (bool) Are they not equal? | ||
186 | */ | ||
187 | bool operator!=( const iterator &oth ) const | ||
188 | { | ||
189 | return ( pLink != oth.pLink ); | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * Not equals comparison operator. | ||
194 | *@param pOth (const Link *) The link to compare to. | ||
195 | *@returns (bool) Are they not equal? | ||
196 | */ | ||
197 | bool operator!=( const Link *pOth ) const | ||
198 | { | ||
199 | return ( pLink != pOth ); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * Dereference operator. | ||
204 | *@returns (value_type &) The value. | ||
205 | */ | ||
206 | value &operator*() | ||
207 | { | ||
208 | return *(pLink->pValue); | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * Pointer access operator. | ||
213 | *@returns (value_type *) A pointer to the value. | ||
214 | */ | ||
215 | value *operator->() | ||
216 | { | ||
217 | return pLink->pValue; | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * Increment operator. | ||
222 | */ | ||
223 | iterator &operator++() | ||
224 | { | ||
225 | if( pLink != NULL ) | ||
226 | pLink = pLink->pNext; | ||
227 | return *this; | ||
228 | } | ||
229 | |||
230 | /** | ||
231 | * Decrement operator. | ||
232 | */ | ||
233 | iterator &operator--() | ||
234 | { | ||
235 | if( pLink != NULL ) | ||
236 | pLink = pLink->pPrev; | ||
237 | return *this; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * Increment operator. | ||
242 | */ | ||
243 | iterator &operator++( int ) | ||
244 | { | ||
245 | if( pLink != NULL ) | ||
246 | pLink = pLink->pNext; | ||
247 | return *this; | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * Decrement operator. | ||
252 | */ | ||
253 | iterator &operator--( int ) | ||
254 | { | ||
255 | if( pLink != NULL ) | ||
256 | pLink = pLink->pPrev; | ||
257 | return *this; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * Assignment operator. | ||
262 | *@param oth (const iterator &) The other iterator to set this | ||
263 | * one to. | ||
264 | */ | ||
265 | iterator &operator=( const iterator &oth ) | ||
266 | { | ||
267 | pLink = oth.pLink; | ||
268 | return *this; | ||
269 | } | ||
270 | }; | ||
271 | |||
272 | /** | ||
273 | *@see iterator | ||
274 | */ | ||
275 | typedef struct const_iterator | ||
276 | { | ||
277 | friend class List<value, valuealloc, linkalloc>; | ||
278 | private: | ||
279 | Link *pLink; | ||
280 | const_iterator() : | ||
281 | pLink( NULL ) | ||
282 | { | ||
283 | } | ||
101 | 284 | ||
285 | const_iterator( Link *pLink ) : | ||
286 | pLink( pLink ) | ||
287 | { | ||
288 | } | ||
289 | |||
290 | const_iterator( const iterator &i ) : | ||
291 | pLink( i.pLink ) | ||
292 | { | ||
293 | } | ||
294 | |||
295 | public: | ||
296 | bool operator==( const const_iterator &oth ) const | ||
297 | { | ||
298 | return ( pLink == oth.pLink ); | ||
299 | } | ||
300 | |||
301 | bool operator==( const Link *pOth ) const | ||
302 | { | ||
303 | return ( pLink == pOth ); | ||
304 | } | ||
305 | |||
306 | bool operator!=( const const_iterator &oth ) const | ||
307 | { | ||
308 | return ( pLink != oth.pLink ); | ||
309 | } | ||
310 | |||
311 | bool operator!=( const Link *pOth ) const | ||
312 | { | ||
313 | return ( pLink != pOth ); | ||
314 | } | ||
315 | |||
316 | const value &operator*() | ||
317 | { | ||
318 | return *(pLink->pValue); | ||
319 | } | ||
320 | |||
321 | const value *operator->() | ||
322 | { | ||
323 | return pLink->pValue; | ||
324 | } | ||
325 | |||
326 | const_iterator &operator++() | ||
327 | { | ||
328 | if( pLink != NULL ) | ||
329 | pLink = pLink->pNext; | ||
330 | return *this; | ||
331 | } | ||
332 | |||
333 | const_iterator &operator--() | ||
334 | { | ||
335 | if( pLink != NULL ) | ||
336 | pLink = pLink->pPrev; | ||
337 | return *this; | ||
338 | } | ||
339 | |||
340 | const_iterator &operator++( int ) | ||
341 | { | ||
342 | if( pLink != NULL ) | ||
343 | pLink = pLink->pNext; | ||
344 | return *this; | ||
345 | } | ||
346 | |||
347 | const_iterator &operator--( int ) | ||
348 | { | ||
349 | if( pLink != NULL ) | ||
350 | pLink = pLink->pPrev; | ||
351 | return *this; | ||
352 | } | ||
353 | |||
354 | const_iterator &operator=( const iterator &oth ) | ||
355 | { | ||
356 | pLink = oth.pLink; | ||
357 | return *this; | ||
358 | } | ||
359 | |||
360 | const_iterator &operator=( const const_iterator &oth ) | ||
361 | { | ||
362 | pLink = oth.pLink; | ||
363 | return *this; | ||
364 | } | ||
365 | }; | ||
366 | |||
367 | /** | ||
368 | * Get an iterator pointing to the first item in the list. | ||
369 | *@returns (iterator) | ||
370 | */ | ||
371 | iterator begin() | ||
372 | { | ||
373 | return iterator( pFirst ); | ||
374 | } | ||
375 | |||
376 | /** | ||
377 | * Get a const iterator pointing to the first item in the list. | ||
378 | *@returns (const const_iterator) | ||
379 | */ | ||
380 | const const_iterator begin() const | ||
381 | { | ||
382 | return const_iterator( pFirst ); | ||
383 | } | ||
384 | |||
385 | /** | ||
386 | * Get an iterator pointing to a place just past the last item in | ||
387 | * the list. | ||
388 | *@returns (const Link *) | ||
389 | */ | ||
390 | const Link *end() const | ||
391 | { | ||
392 | return NULL; | ||
393 | } | ||
394 | |||
395 | /** | ||
396 | * Erase an item from the list. | ||
397 | *@param i (iterator) The item to erase. | ||
398 | */ | ||
399 | void erase( iterator &i ) | ||
400 | { | ||
401 | Link *pCur = i.pLink; | ||
402 | Link *pPrev = pCur->pPrev; | ||
403 | if( pPrev == NULL ) | ||
404 | { | ||
405 | va.destroy( pCur->pValue ); | ||
406 | va.deallocate( pCur->pValue, 1 ); | ||
407 | pFirst = pCur->pNext; | ||
408 | la.destroy( pCur ); | ||
409 | la.deallocate( pCur, 1 ); | ||
410 | if( pFirst == NULL ) | ||
411 | pLast = NULL; | ||
412 | nSize--; | ||
413 | i.pLink = pFirst; | ||
414 | } | ||
415 | else | ||
416 | { | ||
417 | va.destroy( pCur->pValue ); | ||
418 | va.deallocate( pCur->pValue, 1 ); | ||
419 | Link *pTmp = pCur->pNext; | ||
420 | la.destroy( pCur ); | ||
421 | la.deallocate( pCur, 1 ); | ||
422 | pPrev->pNext = pTmp; | ||
423 | if( pTmp != NULL ) | ||
424 | pTmp->pPrev = pPrev; | ||
425 | nSize--; | ||
426 | i.pLink = pTmp; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * Get the current size of the list. | ||
432 | *@returns (int) The current size of the list. | ||
433 | */ | ||
434 | int getSize() const | ||
435 | { | ||
436 | return nSize; | ||
437 | } | ||
438 | |||
439 | /** | ||
440 | * Get the first item in the list. | ||
441 | *@returns (value_type &) The first item in the list. | ||
442 | */ | ||
443 | value &first() | ||
444 | { | ||
445 | return *pFirst->pValue; | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * Get the first item in the list. | ||
450 | *@returns (const value_type &) The first item in the list. | ||
451 | */ | ||
452 | const value &first() const | ||
453 | { | ||
454 | return *pFirst->pValue; | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * Get the last item in the list. | ||
459 | *@returns (value_type &) The last item in the list. | ||
460 | */ | ||
461 | value &last() | ||
462 | { | ||
463 | return *pLast->pValue; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * Get the last item in the list. | ||
468 | *@returns (const value_type &) The last item in the list. | ||
469 | */ | ||
470 | const value &last() const | ||
471 | { | ||
472 | return *pLast->pValue; | ||
473 | } | ||
474 | |||
475 | const bool isEmpty() const | ||
476 | { | ||
477 | return (nSize == 0); | ||
478 | } | ||
479 | |||
480 | private: | ||
481 | Link *pFirst; | ||
482 | Link *pLast; | ||
483 | linkalloc la; | ||
484 | valuealloc va; | ||
485 | int nSize; | ||
486 | }; | ||
487 | } | ||
488 | |||
489 | #endif | ||
diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 0000000..1fc2262 --- /dev/null +++ b/src/logger.cpp | |||
@@ -0,0 +1,131 @@ | |||
1 | #include "bu/logger.h" | ||
2 | #include <stdarg.h> | ||
3 | #include <time.h> | ||
4 | #include <stdio.h> | ||
5 | |||
6 | Bu::Logger::Logger() | ||
7 | { | ||
8 | } | ||
9 | |||
10 | Bu::Logger::~Logger() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | void Bu::Logger::log( int nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...) | ||
15 | { | ||
16 | if( (nLevel&nLevelMask) == 0 ) | ||
17 | return; | ||
18 | |||
19 | va_list ap; | ||
20 | va_start( ap, sFormat ); | ||
21 | char *text; | ||
22 | vasprintf( &text, sFormat, ap ); | ||
23 | va_end(ap); | ||
24 | |||
25 | time_t t = time(NULL); | ||
26 | |||
27 | char *line = NULL; | ||
28 | struct tm *pTime; | ||
29 | pTime = localtime( &t ); | ||
30 | asprintf( | ||
31 | &line, | ||
32 | sLogFormat.getStr(), | ||
33 | pTime->tm_year+1900, | ||
34 | pTime->tm_mon+1, | ||
35 | pTime->tm_mday, | ||
36 | pTime->tm_hour, | ||
37 | pTime->tm_min, | ||
38 | pTime->tm_sec, | ||
39 | nLevel, | ||
40 | sFile, | ||
41 | nLine, | ||
42 | text, | ||
43 | sFunction | ||
44 | ); | ||
45 | write( fileno(stdout), line, strlen(line) ); | ||
46 | free( text ); | ||
47 | free( line ); | ||
48 | } | ||
49 | |||
50 | void Bu::Logger::setFormat( const Bu::FString &str ) | ||
51 | { | ||
52 | sLogFormat = ""; | ||
53 | |||
54 | static char fmts[][4]={ | ||
55 | {'y', 'd', '0', '1'}, | ||
56 | {'m', 'd', '0', '2'}, | ||
57 | {'d', 'd', '0', '3'}, | ||
58 | {'h', 'd', '0', '4'}, | ||
59 | {'M', 'd', '0', '5'}, | ||
60 | {'s', 'd', '0', '6'}, | ||
61 | {'L', 'd', '0', '7'}, | ||
62 | {'f', 's', '0', '8'}, | ||
63 | {'l', 'd', '0', '9'}, | ||
64 | {'t', 's', '1', '0'}, | ||
65 | {'F', 's', '1', '1'}, | ||
66 | {'\0', '\0', '\0', '\0'}, | ||
67 | }; | ||
68 | |||
69 | for( const char *s = str.getStr(); *s; s++ ) | ||
70 | { | ||
71 | if( *s == '%' ) | ||
72 | { | ||
73 | sLogFormat += '%'; | ||
74 | Bu::FString sBuf; | ||
75 | for(;;) | ||
76 | { | ||
77 | s++; | ||
78 | int l; | ||
79 | for( l = 0;; l++ ) | ||
80 | { | ||
81 | if( fmts[l][0] == '\0' ) | ||
82 | { | ||
83 | sBuf += *s; | ||
84 | break; | ||
85 | } | ||
86 | else if( *s == fmts[l][0] ) | ||
87 | { | ||
88 | sLogFormat += fmts[l][2]; | ||
89 | sLogFormat += fmts[l][3]; | ||
90 | sLogFormat += '$'; | ||
91 | sLogFormat += sBuf; | ||
92 | sLogFormat += fmts[l][1]; | ||
93 | break; | ||
94 | } | ||
95 | } | ||
96 | if( fmts[l][0] != '\0' ) | ||
97 | break; | ||
98 | } | ||
99 | } | ||
100 | else | ||
101 | { | ||
102 | sLogFormat += *s; | ||
103 | } | ||
104 | } | ||
105 | sLogFormat += '\n'; | ||
106 | |||
107 | write( fileno(stdout), sLogFormat.getStr(), sLogFormat.getSize() ); | ||
108 | } | ||
109 | |||
110 | void Bu::Logger::setMask( int n ) | ||
111 | { | ||
112 | nLevelMask = n; | ||
113 | } | ||
114 | |||
115 | void Bu::Logger::setLevel( int n ) | ||
116 | { | ||
117 | int j; | ||
118 | for( j = 31; j > 0; j-- ) | ||
119 | { | ||
120 | if( (n&(1<<j)) ) | ||
121 | { | ||
122 | for(; j >= 0; j-- ) | ||
123 | { | ||
124 | n |= (1<<j); | ||
125 | } | ||
126 | nLevelMask = n; | ||
127 | return; | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..f8e1692 --- /dev/null +++ b/src/logger.h | |||
@@ -0,0 +1,112 @@ | |||
1 | #ifndef BU_LOGGER_H | ||
2 | #define BU_LOGGER_H | ||
3 | |||
4 | #include "bu/singleton.h" | ||
5 | #include "bu/fstring.h" | ||
6 | |||
7 | namespace Bu | ||
8 | { | ||
9 | /** | ||
10 | * Simple logging facility. All output goes straight to stdout, unlike the | ||
11 | * old multi-log system. Generally we expect any program complex enough to | ||
12 | * want to use this will have other facilities for processing the logging | ||
13 | * output, but if we need it we can add other output methods. | ||
14 | * | ||
15 | * Currently implemented as a singleton to avoid clutter with globals, you | ||
16 | * generally never want to use the logging system directly, it's annoying. | ||
17 | * Instead use the handy macros lineLog, setLogMask, setLogFormat, and | ||
18 | * setLogLevel. They do all the real work for you. | ||
19 | * | ||
20 | * In the log format, you can specify extra information that will be written | ||
21 | * to the log with every message, and extras in printf style. Use %X flags | ||
22 | * where X is one of the following: | ||
23 | * - L - Logging level of the log message (not the current mask) | ||
24 | * - y - Full year | ||
25 | * - m - Month | ||
26 | * - d - Day of month | ||
27 | * - h - Hour (24-hour format) | ||
28 | * - M - Minutes | ||
29 | * - s - Seconds | ||
30 | * - f - Source file | ||
31 | * - l - Line number | ||
32 | * - F - function name | ||
33 | * - t - Text of message (usually important) | ||
34 | * | ||
35 | * You can include anything extra that you would like, a newline will always | ||
36 | * be added automatically, so no need to worry about that. You can also | ||
37 | * include any extra printf style formatting that you would like, for | ||
38 | * example: "%h:%02M:%02s" for the time 4:02:09 instead of 4:2:9. | ||
39 | * | ||
40 | * It's generally handy to create an enum of values you use as levels during | ||
41 | * program execution (such as error, warning, info, debug, etc). These | ||
42 | * levels should be treated as bitflags, and the most desirable messages, | ||
43 | * i.e. serious errors and the like should be low order (0x01), and the much | ||
44 | * less desirable messages, like debugging info, should be higher order | ||
45 | * (0xF0). During operation you can then set either an explicit mask, | ||
46 | * selecting just the levels that you would like to see printed, or set the | ||
47 | * mask using the setLevel helper function, which simulates verbosity | ||
48 | * levels, enabling every flag lower order than the highest order set bit | ||
49 | * passed. I.E. if you had the following enumerated levels: | ||
50 | * | ||
51 | *@code | ||
52 | enum { | ||
53 | logError = 0x01, | ||
54 | logWarning = 0x02, | ||
55 | logInfo = 0x04, | ||
56 | logDebug = 0x08 | ||
57 | }; | ||
58 | @endcode | ||
59 | * And you set the mask with setMask( logInfo ) the only messages you would | ||
60 | * see are the ones catagorized logInfo. However, if you used | ||
61 | * setLevel( logInfo ) then you would see logInfo, logWarning, and logError | ||
62 | * type messages, since they are lower order. | ||
63 | */ | ||
64 | class Logger : public Bu::Singleton<Bu::Logger> | ||
65 | { | ||
66 | friend class Bu::Singleton<Bu::Logger>; | ||
67 | private: | ||
68 | Logger(); | ||
69 | virtual ~Logger(); | ||
70 | |||
71 | public: | ||
72 | void log( int nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...); | ||
73 | |||
74 | void setFormat( const Bu::FString &str ); | ||
75 | void setMask( int n ); | ||
76 | void setLevel( int n ); | ||
77 | |||
78 | private: | ||
79 | Bu::FString sLogFormat; | ||
80 | int nLevelMask; | ||
81 | }; | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * Use Bu::Logger to log a message at the given level and with the given message | ||
86 | * using printf style formatting, and include extra data such as the current | ||
87 | * file, line number, and function. | ||
88 | */ | ||
89 | #define lineLog( nLevel, sFrmt, ...) \ | ||
90 | Bu::Logger::getInstance().log( nLevel, __FILE__, __PRETTY_FUNCTION__, __LINE__, sFrmt, ##__VA_ARGS__ ) | ||
91 | |||
92 | /** | ||
93 | * Set the Bu::Logger logging mask directly. See Bu::Logger::setMask for | ||
94 | * details. | ||
95 | */ | ||
96 | #define setLogMask( nLevel ) \ | ||
97 | Bu::Logger::getInstance().setMask( nLevel ) | ||
98 | |||
99 | /** | ||
100 | * Set the Bu::Logger format. See Bu::Logger::setFormat for details. | ||
101 | */ | ||
102 | #define setLogFormat( sFrmt ) \ | ||
103 | Bu::Logger::getInstance().setFormat( sFrmt ) | ||
104 | |||
105 | /** | ||
106 | * Set the Bu::Logger logging mask simulating levels. See Bu::Logger::setLevel | ||
107 | * for details. | ||
108 | */ | ||
109 | #define setLogLevel( nLevel ) \ | ||
110 | Bu::Logger::getInstance().setLevel( nLevel ) | ||
111 | |||
112 | #endif | ||
diff --git a/src/main.dox b/src/main.dox new file mode 100644 index 0000000..668d2e3 --- /dev/null +++ b/src/main.dox | |||
@@ -0,0 +1,14 @@ | |||
1 | /** | ||
2 | *@mainpage libbu++ utility library | ||
3 | * | ||
4 | *@section secIntro Introduction | ||
5 | * | ||
6 | * Libbu++ is a C++ library of general utility classes and functions. They | ||
7 | * cover a wide range of topics from streams and sockets to data structures to | ||
8 | * data serialization and xml handling to threading. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /** | ||
13 | *@namespace Bu The core libbu++ namespace, to ensure things don't get muddied. | ||
14 | */ | ||
diff --git a/src/membuf.cpp b/src/membuf.cpp new file mode 100644 index 0000000..45ff5bd --- /dev/null +++ b/src/membuf.cpp | |||
@@ -0,0 +1,120 @@ | |||
1 | #include "bu/membuf.h" | ||
2 | |||
3 | using namespace Bu; | ||
4 | |||
5 | Bu::MemBuf::MemBuf() : | ||
6 | nPos( 0 ) | ||
7 | { | ||
8 | } | ||
9 | |||
10 | Bu::MemBuf::MemBuf( const Bu::FString &str ) : | ||
11 | sBuf( str ), | ||
12 | nPos( 0 ) | ||
13 | { | ||
14 | } | ||
15 | |||
16 | Bu::MemBuf::~MemBuf() | ||
17 | { | ||
18 | } | ||
19 | |||
20 | void Bu::MemBuf::close() | ||
21 | { | ||
22 | } | ||
23 | |||
24 | size_t Bu::MemBuf::read( void *pBuf, size_t nBytes ) | ||
25 | { | ||
26 | if( (size_t)sBuf.getSize()-(size_t)nPos < nBytes ) | ||
27 | nBytes = sBuf.getSize()-nPos; | ||
28 | |||
29 | memcpy( pBuf, sBuf.getStr()+nPos, nBytes ); | ||
30 | nPos += nBytes; | ||
31 | |||
32 | return nBytes; | ||
33 | } | ||
34 | |||
35 | size_t Bu::MemBuf::write( const void *pBuf, size_t nBytes ) | ||
36 | { | ||
37 | sBuf.append( (const char *)pBuf, nBytes ); | ||
38 | nPos += nBytes; | ||
39 | return nBytes; | ||
40 | } | ||
41 | |||
42 | long Bu::MemBuf::tell() | ||
43 | { | ||
44 | return nPos; | ||
45 | } | ||
46 | |||
47 | void Bu::MemBuf::seek( long offset ) | ||
48 | { | ||
49 | nPos += offset; | ||
50 | if( nPos < 0 ) nPos = 0; | ||
51 | else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize(); | ||
52 | } | ||
53 | |||
54 | void Bu::MemBuf::setPos( long pos ) | ||
55 | { | ||
56 | nPos = pos; | ||
57 | if( nPos < 0 ) nPos = 0; | ||
58 | else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize(); | ||
59 | } | ||
60 | |||
61 | void Bu::MemBuf::setPosEnd( long pos ) | ||
62 | { | ||
63 | nPos = sBuf.getSize()-pos; | ||
64 | if( nPos < 0 ) nPos = 0; | ||
65 | else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize(); | ||
66 | } | ||
67 | |||
68 | bool Bu::MemBuf::isEOS() | ||
69 | { | ||
70 | return (nPos == sBuf.getSize()); | ||
71 | } | ||
72 | |||
73 | bool Bu::MemBuf::isOpen() | ||
74 | { | ||
75 | return true; | ||
76 | } | ||
77 | |||
78 | void Bu::MemBuf::flush() | ||
79 | { | ||
80 | } | ||
81 | |||
82 | bool Bu::MemBuf::canRead() | ||
83 | { | ||
84 | return !isEOS(); | ||
85 | } | ||
86 | |||
87 | bool Bu::MemBuf::canWrite() | ||
88 | { | ||
89 | return isEOS(); | ||
90 | } | ||
91 | |||
92 | bool Bu::MemBuf::isReadable() | ||
93 | { | ||
94 | return true; | ||
95 | } | ||
96 | |||
97 | bool Bu::MemBuf::isWritable() | ||
98 | { | ||
99 | return true; | ||
100 | } | ||
101 | |||
102 | bool Bu::MemBuf::isSeekable() | ||
103 | { | ||
104 | return true; | ||
105 | } | ||
106 | |||
107 | bool Bu::MemBuf::isBlocking() | ||
108 | { | ||
109 | return true; | ||
110 | } | ||
111 | |||
112 | void Bu::MemBuf::setBlocking( bool bBlocking ) | ||
113 | { | ||
114 | } | ||
115 | |||
116 | Bu::FString &Bu::MemBuf::getString() | ||
117 | { | ||
118 | return sBuf; | ||
119 | } | ||
120 | |||
diff --git a/src/membuf.h b/src/membuf.h new file mode 100644 index 0000000..8f53d4b --- /dev/null +++ b/src/membuf.h | |||
@@ -0,0 +1,53 @@ | |||
1 | #ifndef BU_MEM_BUF_H | ||
2 | #define BU_MEM_BUF_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | #include "bu/stream.h" | ||
7 | #include "bu/fstring.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | /** | ||
12 | * A memory buffer stream. | ||
13 | */ | ||
14 | class MemBuf : public Stream | ||
15 | { | ||
16 | public: | ||
17 | MemBuf(); | ||
18 | MemBuf( const Bu::FString &str ); | ||
19 | virtual ~MemBuf(); | ||
20 | |||
21 | virtual void close(); | ||
22 | virtual size_t read( void *pBuf, size_t nBytes ); | ||
23 | |||
24 | /** | ||
25 | *@todo Allow writes at the current position, not just appending to | ||
26 | * the current buffer. This is a silly way to do it, but it covers all | ||
27 | * of our bases for now. | ||
28 | */ | ||
29 | virtual size_t write( const void *pBuf, size_t nBytes ); | ||
30 | virtual long tell(); | ||
31 | virtual void seek( long offset ); | ||
32 | virtual void setPos( long pos ); | ||
33 | virtual void setPosEnd( long pos ); | ||
34 | virtual bool isEOS(); | ||
35 | virtual bool isOpen(); | ||
36 | virtual void flush(); | ||
37 | virtual bool canRead(); | ||
38 | virtual bool canWrite(); | ||
39 | virtual bool isReadable(); | ||
40 | virtual bool isWritable(); | ||
41 | virtual bool isSeekable(); | ||
42 | virtual bool isBlocking(); | ||
43 | virtual void setBlocking( bool bBlocking=true ); | ||
44 | |||
45 | Bu::FString &getString(); | ||
46 | |||
47 | private: | ||
48 | Bu::FString sBuf; | ||
49 | long nPos; | ||
50 | }; | ||
51 | } | ||
52 | |||
53 | #endif | ||
diff --git a/src/cgi.cpp b/src/old/cgi.cpp index 1fecbbe..1fecbbe 100644 --- a/src/cgi.cpp +++ b/src/old/cgi.cpp | |||
diff --git a/src/cgi.h b/src/old/cgi.h index 01142b5..01142b5 100644 --- a/src/cgi.h +++ b/src/old/cgi.h | |||
diff --git a/src/configmanagerbase.cpp b/src/old/configmanagerbase.cpp index ac55fe0..ac55fe0 100644 --- a/src/configmanagerbase.cpp +++ b/src/old/configmanagerbase.cpp | |||
diff --git a/src/configmanagerbase.h b/src/old/configmanagerbase.h index 381cc1f..381cc1f 100644 --- a/src/configmanagerbase.h +++ b/src/old/configmanagerbase.h | |||
diff --git a/src/confpair.cpp b/src/old/confpair.cpp index 4741401..4741401 100644 --- a/src/confpair.cpp +++ b/src/old/confpair.cpp | |||
diff --git a/src/confpair.h b/src/old/confpair.h index 56eb06e..56eb06e 100644 --- a/src/confpair.h +++ b/src/old/confpair.h | |||
diff --git a/src/confpairbase.cpp b/src/old/confpairbase.cpp index 1203dc0..1203dc0 100644 --- a/src/confpairbase.cpp +++ b/src/old/confpairbase.cpp | |||
diff --git a/src/confpairbase.h b/src/old/confpairbase.h index 2530756..2530756 100644 --- a/src/confpairbase.h +++ b/src/old/confpairbase.h | |||
diff --git a/src/conftree.cpp b/src/old/conftree.cpp index d9a3a3f..d9a3a3f 100644 --- a/src/conftree.cpp +++ b/src/old/conftree.cpp | |||
diff --git a/src/conftree.h b/src/old/conftree.h index 197b1ef..197b1ef 100644 --- a/src/conftree.h +++ b/src/old/conftree.h | |||
diff --git a/src/connection.cpp b/src/old/connection.cpp index efef144..efef144 100644 --- a/src/connection.cpp +++ b/src/old/connection.cpp | |||
diff --git a/src/connection.h b/src/old/connection.h index 0e991c7..0e991c7 100644 --- a/src/connection.h +++ b/src/old/connection.h | |||
diff --git a/src/connectionmanager.cpp b/src/old/connectionmanager.cpp index ea60b2b..ea60b2b 100644 --- a/src/connectionmanager.cpp +++ b/src/old/connectionmanager.cpp | |||
diff --git a/src/connectionmanager.h b/src/old/connectionmanager.h index cff036b..cff036b 100644 --- a/src/connectionmanager.h +++ b/src/old/connectionmanager.h | |||
diff --git a/src/connectionmonitor.cpp b/src/old/connectionmonitor.cpp index 4f90ee6..4f90ee6 100644 --- a/src/connectionmonitor.cpp +++ b/src/old/connectionmonitor.cpp | |||
diff --git a/src/connectionmonitor.h b/src/old/connectionmonitor.h index 9910556..9910556 100644 --- a/src/connectionmonitor.h +++ b/src/old/connectionmonitor.h | |||
diff --git a/src/flexbuf.cpp b/src/old/flexbuf.cpp index 6d55294..6d55294 100644 --- a/src/flexbuf.cpp +++ b/src/old/flexbuf.cpp | |||
diff --git a/src/flexbuf.h b/src/old/flexbuf.h index 7d7f11a..7d7f11a 100644 --- a/src/flexbuf.h +++ b/src/old/flexbuf.h | |||
diff --git a/src/formula.cpp b/src/old/formula.cpp index cf63cf3..cf63cf3 100644 --- a/src/formula.cpp +++ b/src/old/formula.cpp | |||
diff --git a/src/formula.h b/src/old/formula.h index 939eb09..939eb09 100644 --- a/src/formula.h +++ b/src/old/formula.h | |||
diff --git a/src/http.cpp b/src/old/http.cpp index df7dafe..df7dafe 100644 --- a/src/http.cpp +++ b/src/old/http.cpp | |||
diff --git a/src/http.h b/src/old/http.h index 7e9f9a0..7e9f9a0 100644 --- a/src/http.h +++ b/src/old/http.h | |||
diff --git a/src/httpget.cpp b/src/old/httpget.cpp index ee1f29c..ee1f29c 100644 --- a/src/httpget.cpp +++ b/src/old/httpget.cpp | |||
diff --git a/src/httpget.h b/src/old/httpget.h index 8272641..8272641 100644 --- a/src/httpget.h +++ b/src/old/httpget.h | |||
diff --git a/src/linkedlist.cpp b/src/old/linkedlist.cpp index a9902bc..a9902bc 100644 --- a/src/linkedlist.cpp +++ b/src/old/linkedlist.cpp | |||
diff --git a/src/linkedlist.h b/src/old/linkedlist.h index e430108..e430108 100644 --- a/src/linkedlist.h +++ b/src/old/linkedlist.h | |||
diff --git a/src/linkmessenger.cpp b/src/old/linkmessenger.cpp index 3bd401a..3bd401a 100644 --- a/src/linkmessenger.cpp +++ b/src/old/linkmessenger.cpp | |||
diff --git a/src/linkmessenger.h b/src/old/linkmessenger.h index ed52639..ed52639 100644 --- a/src/linkmessenger.h +++ b/src/old/linkmessenger.h | |||
diff --git a/src/old/list.cpp b/src/old/list.cpp new file mode 100644 index 0000000..18f1a66 --- /dev/null +++ b/src/old/list.cpp | |||
@@ -0,0 +1,10 @@ | |||
1 | #include "list.h" | ||
2 | |||
3 | List::List( ) | ||
4 | { | ||
5 | } | ||
6 | |||
7 | List::~List( ) | ||
8 | { | ||
9 | } | ||
10 | |||
diff --git a/src/old/list.h b/src/old/list.h new file mode 100644 index 0000000..c71b328 --- /dev/null +++ b/src/old/list.h | |||
@@ -0,0 +1,101 @@ | |||
1 | #ifndef LIST_H | ||
2 | #define LIST_H | ||
3 | |||
4 | |||
5 | /** The basic List class ADT. This, on it's own, does absolutely nothing, but | ||
6 | * does define all standard interface functions to access a list. | ||
7 | *@author Mike Buland | ||
8 | */ | ||
9 | class List | ||
10 | { | ||
11 | public: | ||
12 | /** | ||
13 | * Construct a list. | ||
14 | */ | ||
15 | List(); | ||
16 | |||
17 | /** | ||
18 | * Desconstruct a list. | ||
19 | */ | ||
20 | virtual ~List(); | ||
21 | |||
22 | /** Gets the value at a specified index. | ||
23 | *@param nIndex The index of the item to return. | ||
24 | *@returns The specified item, or NULL if the index was beyond the range | ||
25 | * of the list. | ||
26 | *@author Mike Buland | ||
27 | */ | ||
28 | virtual void *getAt( int nIndex ) = 0; | ||
29 | |||
30 | /** Append the given data to the end of the list. This increases the | ||
31 | * size of the list by one. | ||
32 | *@param pData The data to append to the list. | ||
33 | *@author Mike Buland | ||
34 | */ | ||
35 | virtual void append( void *pData ) = 0; | ||
36 | |||
37 | /** Inserts an item at the specified position in the list. The | ||
38 | * new item takes the index that you specify, and all other items | ||
39 | * are moved up one position. The size of the list is increased by | ||
40 | * one. | ||
41 | *@param pData The value to insert into the list. | ||
42 | *@param nPos Where to insert the data into the list. | ||
43 | *@author Mike Buland | ||
44 | */ | ||
45 | virtual void insertBefore( void *pData, int nPos = 0 ) = 0; | ||
46 | |||
47 | /** Determines the size of the list, in elements. | ||
48 | *@returns The size of the list. | ||
49 | *@author Mike Buland | ||
50 | */ | ||
51 | virtual int getSize( ) = 0; | ||
52 | |||
53 | /** Determines if the list is empty or not. | ||
54 | *@returns True if the list is empty, or false if the list has | ||
55 | * data in it (if the size is greater than zero). | ||
56 | *@author Mike Buland | ||
57 | */ | ||
58 | virtual bool isEmpty( ) = 0; | ||
59 | |||
60 | /** Deletes an item at the specified index and moves all other | ||
61 | * values down one index. The size of the list is decreased by one. | ||
62 | *@param nIndex The index of the item to delete. | ||
63 | *@author Mike Buland | ||
64 | */ | ||
65 | virtual void deleteAt( int nIndex ) = 0; | ||
66 | |||
67 | /** Completely empties the list, and sets the effective size to | ||
68 | * zero. | ||
69 | *@author Mike Buland | ||
70 | */ | ||
71 | virtual void empty() = 0; | ||
72 | |||
73 | /** Sets the size of the list. This can be larger or smaller | ||
74 | * than what it was previously. If larger, new blank items will | ||
75 | * be added to the end of the list. If smaller than the old list | ||
76 | * items will be deleted from the end. | ||
77 | *@param nNewSize The new size of the list. | ||
78 | *@author Mike Buland | ||
79 | */ | ||
80 | virtual void setSize( int nNewSize ) = 0; | ||
81 | |||
82 | /** Sets a member at a specified location to a new value. | ||
83 | * If the member being set is outside of the range of the | ||
84 | * current list it should be expanded. | ||
85 | *@param nIndex The zero-based index of the item to change. | ||
86 | *@param pData The new value for that index. | ||
87 | *@author Mike Buland | ||
88 | */ | ||
89 | virtual void setAt( int nIndex, void *pData ) = 0; | ||
90 | |||
91 | /** Makes the List work like an array. Just say listObj[2] to get | ||
92 | * the third element. | ||
93 | *@param nIndex The index to access in the list. | ||
94 | *@returns A pointer to the data at element index. | ||
95 | *@author Mike Buland | ||
96 | */ | ||
97 | void *operator[]( int nIndex ) { return getAt( nIndex ); }; | ||
98 | }; | ||
99 | |||
100 | #endif | ||
101 | |||
diff --git a/src/md5.cpp b/src/old/md5.cpp index c0cacdd..c0cacdd 100644 --- a/src/md5.cpp +++ b/src/old/md5.cpp | |||
diff --git a/src/md5.h b/src/old/md5.h index 7f77d83..7f77d83 100644 --- a/src/md5.h +++ b/src/old/md5.h | |||
diff --git a/src/multilog.cpp b/src/old/multilog.cpp index 143ee89..143ee89 100644 --- a/src/multilog.cpp +++ b/src/old/multilog.cpp | |||
diff --git a/src/multilog.h b/src/old/multilog.h index 692095a..692095a 100644 --- a/src/multilog.h +++ b/src/old/multilog.h | |||
diff --git a/src/multilogchannel.cpp b/src/old/multilogchannel.cpp index ee4c9bf..ee4c9bf 100644 --- a/src/multilogchannel.cpp +++ b/src/old/multilogchannel.cpp | |||
diff --git a/src/multilogchannel.h b/src/old/multilogchannel.h index d891a65..d891a65 100644 --- a/src/multilogchannel.h +++ b/src/old/multilogchannel.h | |||
diff --git a/src/multilogtext.cpp b/src/old/multilogtext.cpp index 4337cc9..4337cc9 100644 --- a/src/multilogtext.cpp +++ b/src/old/multilogtext.cpp | |||
diff --git a/src/multilogtext.h b/src/old/multilogtext.h index 197aef1..197aef1 100644 --- a/src/multilogtext.h +++ b/src/old/multilogtext.h | |||
diff --git a/src/ordhash.cpp b/src/old/ordhash.cpp index 77cbd61..77cbd61 100644 --- a/src/ordhash.cpp +++ b/src/old/ordhash.cpp | |||
diff --git a/src/ordhash.h b/src/old/ordhash.h index e946f95..e946f95 100644 --- a/src/ordhash.h +++ b/src/old/ordhash.h | |||
diff --git a/src/pqueue.cpp b/src/old/pqueue.cpp index 1f0b8b5..1f0b8b5 100644 --- a/src/pqueue.cpp +++ b/src/old/pqueue.cpp | |||
diff --git a/src/pqueue.h b/src/old/pqueue.h index 8307d56..8307d56 100644 --- a/src/pqueue.h +++ b/src/old/pqueue.h | |||
diff --git a/src/old/protocol.cpp b/src/old/protocol.cpp new file mode 100644 index 0000000..78b3ee2 --- /dev/null +++ b/src/old/protocol.cpp | |||
@@ -0,0 +1,20 @@ | |||
1 | #include "protocol.h" | ||
2 | |||
3 | Protocol::Protocol() | ||
4 | { | ||
5 | pConnection = NULL; | ||
6 | } | ||
7 | |||
8 | Protocol::~Protocol() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | void Protocol::setConnection( Connection *pNewConnection ) | ||
13 | { | ||
14 | pConnection = pNewConnection; | ||
15 | } | ||
16 | |||
17 | Connection *Protocol::getConnection() | ||
18 | { | ||
19 | return pConnection; | ||
20 | } | ||
diff --git a/src/old/protocol.h b/src/old/protocol.h new file mode 100644 index 0000000..09e1c98 --- /dev/null +++ b/src/old/protocol.h | |||
@@ -0,0 +1,62 @@ | |||
1 | #ifndef PROTOCOL_H | ||
2 | #define PROTOCOL_H | ||
3 | |||
4 | #include "connection.h" | ||
5 | |||
6 | /** This is the template for a class that handles specialized input and output | ||
7 | * to connections of different types with different protocols. | ||
8 | *@author Mike Buland | ||
9 | */ | ||
10 | class Protocol | ||
11 | { | ||
12 | public: | ||
13 | /** Constructor */ | ||
14 | Protocol(); | ||
15 | /** Deconstructor */ | ||
16 | virtual ~Protocol(); | ||
17 | |||
18 | /** | ||
19 | * Function is called every time there is new data on the line. This is | ||
20 | * called directly from the Connection class to process data. This is not | ||
21 | * called whever there is pending data on the input, but every time new data | ||
22 | * is added to the input buffer. | ||
23 | *@returns True if processing went alright, false if something went wrong, | ||
24 | * I suppose. In truth this value is thrown away right now. | ||
25 | *@todo Either make a return value of false mean something, or make these | ||
26 | * void. | ||
27 | */ | ||
28 | virtual bool onNewData()=0; | ||
29 | |||
30 | /** | ||
31 | * Function is called when there is a new connection. This should only | ||
32 | * happen once per Protocol object, but gives each protocol object a | ||
33 | * chance to perform connection handshaking and initialization at a point | ||
34 | * where they know that they have a handle to an active Connection. | ||
35 | *@returns See onNewData | ||
36 | */ | ||
37 | virtual bool onNewConnection()=0; | ||
38 | |||
39 | virtual void onNewClientConnection(){}; | ||
40 | |||
41 | virtual void poll(){}; | ||
42 | |||
43 | /** | ||
44 | * Sets the Protocol's Connection object. This is rather important, and | ||
45 | * handled usually by the ConnectionManager. | ||
46 | *@param pNewConnection The Connection object that this protocol will use to | ||
47 | * deal with the outside world. | ||
48 | */ | ||
49 | void setConnection( class Connection *pNewConnection ); | ||
50 | |||
51 | /** | ||
52 | * Get a pointer to this object's Connection object, or NULL if one was | ||
53 | * never set. If used with the ConnectionManager that should never happen. | ||
54 | *@returns A pointer to the active Connection. | ||
55 | */ | ||
56 | Connection *getConnection(); | ||
57 | |||
58 | private: | ||
59 | class Connection *pConnection; /**< The pointer to the Connection. */ | ||
60 | }; | ||
61 | |||
62 | #endif | ||
diff --git a/src/protocoltelnet.cpp b/src/old/protocoltelnet.cpp index b169a51..b169a51 100644 --- a/src/protocoltelnet.cpp +++ b/src/old/protocoltelnet.cpp | |||
diff --git a/src/protocoltelnet.h b/src/old/protocoltelnet.h index a6d2e49..a6d2e49 100644 --- a/src/protocoltelnet.h +++ b/src/old/protocoltelnet.h | |||
diff --git a/src/queue.cpp b/src/old/queue.cpp index 42999fe..42999fe 100644 --- a/src/queue.cpp +++ b/src/old/queue.cpp | |||
diff --git a/src/queue.h b/src/old/queue.h index 692f5d8..692f5d8 100644 --- a/src/queue.h +++ b/src/old/queue.h | |||
diff --git a/src/ringlist.cpp b/src/old/ringlist.cpp index 9efbbc4..9efbbc4 100644 --- a/src/ringlist.cpp +++ b/src/old/ringlist.cpp | |||
diff --git a/src/ringlist.h b/src/old/ringlist.h index bc069f3..bc069f3 100644 --- a/src/ringlist.h +++ b/src/old/ringlist.h | |||
diff --git a/src/sbuffer.cpp b/src/old/sbuffer.cpp index f84f8a3..f84f8a3 100644 --- a/src/sbuffer.cpp +++ b/src/old/sbuffer.cpp | |||
diff --git a/src/sbuffer.h b/src/old/sbuffer.h index 65feb71..65feb71 100644 --- a/src/sbuffer.h +++ b/src/old/sbuffer.h | |||
diff --git a/src/serializerbinary.cpp b/src/old/serializerbinary.cpp index ea7ed93..ea7ed93 100644 --- a/src/serializerbinary.cpp +++ b/src/old/serializerbinary.cpp | |||
diff --git a/src/serializerbinary.h b/src/old/serializerbinary.h index 8510fcd..8510fcd 100644 --- a/src/serializerbinary.h +++ b/src/old/serializerbinary.h | |||
diff --git a/src/serializerbzip2.cpp b/src/old/serializerbzip2.cpp index bafabc8..bafabc8 100644 --- a/src/serializerbzip2.cpp +++ b/src/old/serializerbzip2.cpp | |||
diff --git a/src/serializerbzip2.h b/src/old/serializerbzip2.h index 4aeb22e..4aeb22e 100644 --- a/src/serializerbzip2.h +++ b/src/old/serializerbzip2.h | |||
diff --git a/src/serializerconnection.cpp b/src/old/serializerconnection.cpp index 2934c8b..2934c8b 100644 --- a/src/serializerconnection.cpp +++ b/src/old/serializerconnection.cpp | |||
diff --git a/src/serializerconnection.h b/src/old/serializerconnection.h index e8d85c6..e8d85c6 100644 --- a/src/serializerconnection.h +++ b/src/old/serializerconnection.h | |||
diff --git a/src/serializertext.cpp b/src/old/serializertext.cpp index 9cf4394..9cf4394 100644 --- a/src/serializertext.cpp +++ b/src/old/serializertext.cpp | |||
diff --git a/src/serializertext.h b/src/old/serializertext.h index 01b7f7b..01b7f7b 100644 --- a/src/serializertext.h +++ b/src/old/serializertext.h | |||
diff --git a/src/sha1.cpp b/src/old/sha1.cpp index 8270c3b..8270c3b 100644 --- a/src/sha1.cpp +++ b/src/old/sha1.cpp | |||
diff --git a/src/sha1.h b/src/old/sha1.h index ab6081d..ab6081d 100644 --- a/src/sha1.h +++ b/src/old/sha1.h | |||
diff --git a/src/stack.cpp b/src/old/stack.cpp index 8d9565c..8d9565c 100644 --- a/src/stack.cpp +++ b/src/old/stack.cpp | |||
diff --git a/src/stack.h b/src/old/stack.h index 30e2a19..30e2a19 100644 --- a/src/stack.h +++ b/src/old/stack.h | |||
diff --git a/src/staticstring.cpp b/src/old/staticstring.cpp index 60f130f..60f130f 100644 --- a/src/staticstring.cpp +++ b/src/old/staticstring.cpp | |||
diff --git a/src/staticstring.h b/src/old/staticstring.h index 4c3f7b8..4c3f7b8 100644 --- a/src/staticstring.h +++ b/src/old/staticstring.h | |||
diff --git a/src/stringrep.cpp b/src/old/stringrep.cpp index a505f8a..a505f8a 100644 --- a/src/stringrep.cpp +++ b/src/old/stringrep.cpp | |||
diff --git a/src/stringrep.h b/src/old/stringrep.h index eaa4a12..eaa4a12 100644 --- a/src/stringrep.h +++ b/src/old/stringrep.h | |||
diff --git a/src/tests/clistress.cpp b/src/old/tests/clistress.cpp index 6b0ac66..6b0ac66 100644 --- a/src/tests/clistress.cpp +++ b/src/old/tests/clistress.cpp | |||
diff --git a/src/tests/confpair.cpp b/src/old/tests/confpair.cpp index fb1b0d3..fb1b0d3 100644 --- a/src/tests/confpair.cpp +++ b/src/old/tests/confpair.cpp | |||
diff --git a/src/tests/connect.cpp b/src/old/tests/connect.cpp index a9fca64..a9fca64 100644 --- a/src/tests/connect.cpp +++ b/src/old/tests/connect.cpp | |||
diff --git a/src/tests/exception.cpp b/src/old/tests/exception.cpp index 6417692..6417692 100644 --- a/src/tests/exception.cpp +++ b/src/old/tests/exception.cpp | |||
diff --git a/src/tests/formula.cpp b/src/old/tests/formula.cpp index 976b039..976b039 100644 --- a/src/tests/formula.cpp +++ b/src/old/tests/formula.cpp | |||
diff --git a/src/old/tests/hash.cpp b/src/old/tests/hash.cpp new file mode 100644 index 0000000..2fc6968 --- /dev/null +++ b/src/old/tests/hash.cpp | |||
@@ -0,0 +1,116 @@ | |||
1 | #include "hash.h" | ||
2 | #include "staticstring.h" | ||
3 | |||
4 | int main() | ||
5 | { | ||
6 | const char *names[]={ | ||
7 | "Homer the Great", | ||
8 | "And Maggie Makes Three", | ||
9 | "Bart's Comet", | ||
10 | "Homie The Clown", | ||
11 | "Bart Vs Australia", | ||
12 | "Homer vs Patty and Selma", | ||
13 | "A star is burns", | ||
14 | "Lisa's Wedding", | ||
15 | "Two Dozen and One Greyhounds", | ||
16 | "The PTA Disbands", | ||
17 | "Round Springfield", | ||
18 | "The Springfield connection", | ||
19 | "Lemon of Troy", | ||
20 | "Who Shot Mr. Burns (Pt. 1)", | ||
21 | "Who Shot Mr. Burns (pt. 2)", | ||
22 | "Radioactive Man", | ||
23 | "Home Sweet Homediddly-dum-doodly", | ||
24 | "Bart Sells His Soul", | ||
25 | "Lisa the Vegetarian", | ||
26 | "Treehouse of horror VI", | ||
27 | "King Size Homer", | ||
28 | "Mother Simpson", | ||
29 | "Sideshow Bob's Last Gleaming", | ||
30 | "The Simpson's 138th Show Spectacular", | ||
31 | "Marge Be Not Proud", | ||
32 | "Team Homer", | ||
33 | "Two Bad Neighbors", | ||
34 | "Scenes From the Class Struggle in Springfield", | ||
35 | "Bart the Fink", | ||
36 | "Lisa the Iconoclast", | ||
37 | "Homer the Smithers", | ||
38 | "The Day the Violence Died", | ||
39 | "A Fish Called Selma", | ||
40 | "Bart on the road", | ||
41 | "22 Short Films about Springfield", | ||
42 | "The Curse of the Flying Hellfish", | ||
43 | "Much Apu about Nothing", | ||
44 | "Homerpalooza", | ||
45 | "The Summer of 4 Ft 2", | ||
46 | "Treehouse of Horror VII", | ||
47 | "You Only Move Twice", | ||
48 | "The Homer They Fall", | ||
49 | "Burns Baby Burns", | ||
50 | "Bart After Dark", | ||
51 | "A Millhouse Divided", | ||
52 | "Lisas Date With Destiny", | ||
53 | "Hurricane Neddy", | ||
54 | "The Mysterious Voyage of Our Homer", | ||
55 | "The Springfield Files", | ||
56 | "The Twisted World of Marge Simpson", | ||
57 | "Mountain of Madness", | ||
58 | NULL | ||
59 | }; | ||
60 | |||
61 | Hash<const char *, int> sTest; | ||
62 | |||
63 | printf("Inserting\n-------------------\n\n"); | ||
64 | for( int j = 0; j < 33; j++ ) | ||
65 | { | ||
66 | sTest[names[j]] = j; | ||
67 | } | ||
68 | |||
69 | printf("Test1: %d, Test2: %d\n", sTest.has("Lemon of Troy"), sTest.has(std::string("Lemon of Troy").c_str() ) ); | ||
70 | |||
71 | sTest.has(std::string("Lemon of Troy").c_str() ); | ||
72 | |||
73 | printf("Getting\n-------------------\n\n"); | ||
74 | |||
75 | sTest.erase("Homer the Great"); | ||
76 | sTest["Bart's Comet"].erase(); | ||
77 | |||
78 | for( Hash<const char *, int>::iterator i = sTest.begin(); | ||
79 | i != sTest.end(); i++ ) | ||
80 | { | ||
81 | Hash<const char *, int>::iterator j = i; | ||
82 | printf("%d: %s\n", (*j).second, (*j).first ); | ||
83 | } | ||
84 | |||
85 | printf("Testing\n-------------------\n\n"); | ||
86 | for( int j = 0; j < 33; j++ ) | ||
87 | { | ||
88 | if( sTest.has(names[j]) ) | ||
89 | { | ||
90 | if( sTest[names[j]] != j ) | ||
91 | { | ||
92 | printf("'%s' should be %d, is %d\n", | ||
93 | names[j], j, | ||
94 | sTest[names[j]].value() | ||
95 | ); | ||
96 | } | ||
97 | } | ||
98 | else | ||
99 | { | ||
100 | printf("Missing element %d, '%s'\n", j, names[j] ); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | printf("Clearing\n-------------------\n\n"); | ||
105 | |||
106 | sTest.clear(); | ||
107 | |||
108 | for( Hash<const char *, int>::iterator i = sTest.begin(); | ||
109 | i != sTest.end(); i++ ) | ||
110 | { | ||
111 | Hash<const char *, int>::iterator j = i; | ||
112 | printf("%d: %s\n", (*j).second, (*j).first ); | ||
113 | } | ||
114 | |||
115 | } | ||
116 | |||
diff --git a/src/tests/hashtest.cpp b/src/old/tests/hashtest.cpp index eaa84a0..eaa84a0 100644 --- a/src/tests/hashtest.cpp +++ b/src/old/tests/hashtest.cpp | |||
diff --git a/src/tests/hashtest2.cpp b/src/old/tests/hashtest2.cpp index 74700fd..74700fd 100644 --- a/src/tests/hashtest2.cpp +++ b/src/old/tests/hashtest2.cpp | |||
diff --git a/src/tests/httpsrv/httpconnectionmonitor.cpp b/src/old/tests/httpsrv/httpconnectionmonitor.cpp index 51d82f3..51d82f3 100644 --- a/src/tests/httpsrv/httpconnectionmonitor.cpp +++ b/src/old/tests/httpsrv/httpconnectionmonitor.cpp | |||
diff --git a/src/tests/httpsrv/httpconnectionmonitor.h b/src/old/tests/httpsrv/httpconnectionmonitor.h index 30c0afd..30c0afd 100644 --- a/src/tests/httpsrv/httpconnectionmonitor.h +++ b/src/old/tests/httpsrv/httpconnectionmonitor.h | |||
diff --git a/src/tests/httpsrv/main.cpp b/src/old/tests/httpsrv/main.cpp index 2f1563c..2f1563c 100644 --- a/src/tests/httpsrv/main.cpp +++ b/src/old/tests/httpsrv/main.cpp | |||
diff --git a/src/tests/log.cpp b/src/old/tests/log.cpp index d7cfa0b..d7cfa0b 100644 --- a/src/tests/log.cpp +++ b/src/old/tests/log.cpp | |||
diff --git a/src/tests/md5test.cpp b/src/old/tests/md5test.cpp index 6f832df..6f832df 100644 --- a/src/tests/md5test.cpp +++ b/src/old/tests/md5test.cpp | |||
diff --git a/src/tests/ordhash.cpp b/src/old/tests/ordhash.cpp index f1d96ec..f1d96ec 100644 --- a/src/tests/ordhash.cpp +++ b/src/old/tests/ordhash.cpp | |||
diff --git a/src/tests/param.cpp b/src/old/tests/param.cpp index a4d2824..a4d2824 100644 --- a/src/tests/param.cpp +++ b/src/old/tests/param.cpp | |||
diff --git a/src/tests/param.h b/src/old/tests/param.h index 2756b69..2756b69 100644 --- a/src/tests/param.h +++ b/src/old/tests/param.h | |||
diff --git a/src/tests/plugin/main.cpp b/src/old/tests/plugin/main.cpp index 51c8390..51c8390 100644 --- a/src/tests/plugin/main.cpp +++ b/src/old/tests/plugin/main.cpp | |||
diff --git a/src/tests/plugin/plugin.cpp b/src/old/tests/plugin/plugin.cpp index ea558fd..ea558fd 100644 --- a/src/tests/plugin/plugin.cpp +++ b/src/old/tests/plugin/plugin.cpp | |||
diff --git a/src/tests/plugin/plugin.h b/src/old/tests/plugin/plugin.h index f726867..f726867 100644 --- a/src/tests/plugin/plugin.h +++ b/src/old/tests/plugin/plugin.h | |||
diff --git a/src/tests/qsort.cpp b/src/old/tests/qsort.cpp index 28c6f03..28c6f03 100644 --- a/src/tests/qsort.cpp +++ b/src/old/tests/qsort.cpp | |||
diff --git a/src/tests/sbuffer.cpp b/src/old/tests/sbuffer.cpp index 02798cb..02798cb 100644 --- a/src/tests/sbuffer.cpp +++ b/src/old/tests/sbuffer.cpp | |||
diff --git a/src/tests/serialize.cpp b/src/old/tests/serialize.cpp index e233704..e233704 100644 --- a/src/tests/serialize.cpp +++ b/src/old/tests/serialize.cpp | |||
diff --git a/src/tests/serializetext.cpp b/src/old/tests/serializetext.cpp index f6be7d3..f6be7d3 100644 --- a/src/tests/serializetext.cpp +++ b/src/old/tests/serializetext.cpp | |||
diff --git a/src/tests/sha1.cpp b/src/old/tests/sha1.cpp index df3113c..df3113c 100644 --- a/src/tests/sha1.cpp +++ b/src/old/tests/sha1.cpp | |||
diff --git a/src/tests/sptr.cpp b/src/old/tests/sptr.cpp index 252463b..38d3675 100644 --- a/src/tests/sptr.cpp +++ b/src/old/tests/sptr.cpp | |||
@@ -9,12 +9,12 @@ public: | |||
9 | printf("Created.\n"); | 9 | printf("Created.\n"); |
10 | } | 10 | } |
11 | 11 | ||
12 | virtual ~Annoy() | 12 | ~Annoy() |
13 | { | 13 | { |
14 | printf("Destroyed.\n"); | 14 | printf("Destroyed.\n"); |
15 | } | 15 | } |
16 | 16 | ||
17 | virtual void go() | 17 | void go() |
18 | { | 18 | { |
19 | printf("%d: I'm annoying.\n", ++nCnt); | 19 | printf("%d: I'm annoying.\n", ++nCnt); |
20 | } | 20 | } |
@@ -22,22 +22,6 @@ public: | |||
22 | int nCnt; | 22 | int nCnt; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | class Annoy2: public Annoy | ||
26 | { | ||
27 | public: | ||
28 | Annoy2(){}; | ||
29 | virtual ~Annoy2(){}; | ||
30 | virtual void go() | ||
31 | { | ||
32 | printf("{{I'm Annoy2!!}} "); | ||
33 | Annoy::go(); | ||
34 | } | ||
35 | virtual void go2() | ||
36 | { | ||
37 | printf("This is me, on my own...\n"); | ||
38 | } | ||
39 | }; | ||
40 | |||
41 | void beAnnoying( SPtr<Annoy> bob ) | 25 | void beAnnoying( SPtr<Annoy> bob ) |
42 | { | 26 | { |
43 | printf("bob-Count: %d\n", bob.count() ); | 27 | printf("bob-Count: %d\n", bob.count() ); |
@@ -46,7 +30,7 @@ void beAnnoying( SPtr<Annoy> bob ) | |||
46 | 30 | ||
47 | int main() | 31 | int main() |
48 | { | 32 | { |
49 | SPtr<Annoy> pt( new Annoy2 ); | 33 | SPtr<Annoy> pt( new Annoy ); |
50 | printf("Count: %d\n", pt.count() ); | 34 | printf("Count: %d\n", pt.count() ); |
51 | pt->go(); | 35 | pt->go(); |
52 | 36 | ||
@@ -63,14 +47,6 @@ int main() | |||
63 | pt3->go(); | 47 | pt3->go(); |
64 | 48 | ||
65 | beAnnoying( pt3 ); | 49 | beAnnoying( pt3 ); |
66 | |||
67 | { | ||
68 | SPtr<Annoy2> pt4( SPtrCast<Annoy2>( pt3 ) ); | ||
69 | printf("Count: %d\n", pt4.count() ); | ||
70 | |||
71 | pt4->go2(); | ||
72 | } | ||
73 | printf("Count: %d\n", pt.count() ); | ||
74 | } | 50 | } |
75 | printf("Count: %d\n", pt.count() ); | 51 | printf("Count: %d\n", pt.count() ); |
76 | } | 52 | } |
diff --git a/src/tests/srvstress.cpp b/src/old/tests/srvstress.cpp index d9a9a1c..d9a9a1c 100644 --- a/src/tests/srvstress.cpp +++ b/src/old/tests/srvstress.cpp | |||
diff --git a/src/tests/strhash.cpp b/src/old/tests/strhash.cpp index f6528ca..f6528ca 100644 --- a/src/tests/strhash.cpp +++ b/src/old/tests/strhash.cpp | |||
diff --git a/src/tests/teltest/main.cpp b/src/old/tests/teltest/main.cpp index 5d3ec26..5d3ec26 100644 --- a/src/tests/teltest/main.cpp +++ b/src/old/tests/teltest/main.cpp | |||
diff --git a/src/tests/teltest/telnetmonitor.cpp b/src/old/tests/teltest/telnetmonitor.cpp index 65954eb..65954eb 100644 --- a/src/tests/teltest/telnetmonitor.cpp +++ b/src/old/tests/teltest/telnetmonitor.cpp | |||
diff --git a/src/tests/teltest/telnetmonitor.h b/src/old/tests/teltest/telnetmonitor.h index ba5761e..ba5761e 100644 --- a/src/tests/teltest/telnetmonitor.h +++ b/src/old/tests/teltest/telnetmonitor.h | |||
diff --git a/src/tests/xmlreadtest.cpp b/src/old/tests/xmlreadtest.cpp index d061810..d061810 100644 --- a/src/tests/xmlreadtest.cpp +++ b/src/old/tests/xmlreadtest.cpp | |||
diff --git a/src/tests/xmlrepltest.cpp b/src/old/tests/xmlrepltest.cpp index 9667705..9667705 100644 --- a/src/tests/xmlrepltest.cpp +++ b/src/old/tests/xmlrepltest.cpp | |||
diff --git a/src/tests/xmlwritetest.cpp b/src/old/tests/xmlwritetest.cpp index a22d19d..a22d19d 100644 --- a/src/tests/xmlwritetest.cpp +++ b/src/old/tests/xmlwritetest.cpp | |||
diff --git a/src/tokenstring.cpp b/src/old/tokenstring.cpp index e57ba69..e57ba69 100644 --- a/src/tokenstring.cpp +++ b/src/old/tokenstring.cpp | |||
diff --git a/src/tokenstring.h b/src/old/tokenstring.h index 42f7309..42f7309 100644 --- a/src/tokenstring.h +++ b/src/old/tokenstring.h | |||
diff --git a/src/tqsort.h b/src/old/tqsort.h index c836b4f..c836b4f 100644 --- a/src/tqsort.h +++ b/src/old/tqsort.h | |||
diff --git a/src/unit/hashtable/hashtable.cpp b/src/old/unit/hashtable/hashtable.cpp index b2e1cf5..b2e1cf5 100644 --- a/src/unit/hashtable/hashtable.cpp +++ b/src/old/unit/hashtable/hashtable.cpp | |||
diff --git a/src/unit/xml/xml.cpp b/src/old/unit/xml/xml.cpp index e4d779c..e4d779c 100644 --- a/src/unit/xml/xml.cpp +++ b/src/old/unit/xml/xml.cpp | |||
diff --git a/src/xmldocument.cpp b/src/old/xmldocument.cpp index d7867d5..95b9788 100644 --- a/src/xmldocument.cpp +++ b/src/old/xmldocument.cpp | |||
@@ -1,6 +1,6 @@ | |||
1 | #include <stdio.h> | 1 | #include <stdio.h> |
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include "xmlwriter.h" | 3 | #include "xmldocument.h" |
4 | 4 | ||
5 | XmlDocument::XmlDocument( XmlNode *pRoot ) | 5 | XmlDocument::XmlDocument( XmlNode *pRoot ) |
6 | { | 6 | { |
@@ -17,28 +17,23 @@ XmlDocument::~XmlDocument() | |||
17 | } | 17 | } |
18 | } | 18 | } |
19 | 19 | ||
20 | void XmlDocument::addNode( const char *sName, const char *sContent, bool bClose ) | 20 | void XmlDocument::addNode( const Bu::FString &sName ) |
21 | { | 21 | { |
22 | if( pRoot == NULL ) | 22 | if( pRoot == NULL ) |
23 | { | 23 | { |
24 | // This is the first node, so ignore position and just insert it. | 24 | // This is the first node, so ignore position and just insert it. |
25 | pCurrent = pRoot = new XmlNode( sName, NULL, sContent ); | 25 | pCurrent = pRoot = new XmlNode( sName ); |
26 | } | 26 | } |
27 | else | 27 | else |
28 | { | 28 | { |
29 | pCurrent = pCurrent->addChild( sName, sContent ); | 29 | pCurrent = pCurrent->addChild( sName ); |
30 | } | ||
31 | |||
32 | if( bClose ) | ||
33 | { | ||
34 | closeNode(); | ||
35 | } | 30 | } |
36 | } | 31 | } |
37 | 32 | /* | |
38 | void XmlDocument::setName( const char *sName ) | 33 | void XmlDocument::setName( const char *sName ) |
39 | { | 34 | { |
40 | pCurrent->setName( sName ); | 35 | pCurrent->setName( sName ); |
41 | } | 36 | }*/ |
42 | 37 | ||
43 | bool XmlDocument::isCompleted() | 38 | bool XmlDocument::isCompleted() |
44 | { | 39 | { |
@@ -143,7 +138,8 @@ void XmlDocument::setContent( const char *sContent ) | |||
143 | { | 138 | { |
144 | if( pCurrent ) | 139 | if( pCurrent ) |
145 | { | 140 | { |
146 | pCurrent->setContent( sContent ); | 141 | printf("XmlDocument::setContent: not yet implemented.\n"); |
142 | //pCurrent->setContent( sContent ); | ||
147 | } | 143 | } |
148 | } | 144 | } |
149 | 145 | ||
diff --git a/src/xmldocument.h b/src/old/xmldocument.h index 6671c41..e0c36eb 100644 --- a/src/xmldocument.h +++ b/src/old/xmldocument.h | |||
@@ -39,13 +39,7 @@ public: | |||
39 | * the node and setting the content and name. If this is set to true the | 39 | * the node and setting the content and name. If this is set to true the |
40 | * node is appended, but the context node doesn't change. | 40 | * node is appended, but the context node doesn't change. |
41 | */ | 41 | */ |
42 | void addNode( const char *sName=NULL, const char *sContent=NULL, bool bClose=false ); | 42 | void addNode( const Bu::FString &sName ); |
43 | |||
44 | /** | ||
45 | * Set the name of the current node context. | ||
46 | *@param sName The new name of the node. | ||
47 | */ | ||
48 | void setName( const char *sName ); | ||
49 | 43 | ||
50 | /** | 44 | /** |
51 | * Close the current node context. This will move the current context to | 45 | * Close the current node context. This will move the current context to |
diff --git a/src/xmlfilereader.cpp b/src/old/xmlfilereader.cpp index ed674a8..ed674a8 100644 --- a/src/xmlfilereader.cpp +++ b/src/old/xmlfilereader.cpp | |||
diff --git a/src/xmlfilereader.h b/src/old/xmlfilereader.h index e3e02c2..e3e02c2 100644 --- a/src/xmlfilereader.h +++ b/src/old/xmlfilereader.h | |||
diff --git a/src/xmlfilewriter.cpp b/src/old/xmlfilewriter.cpp index 3c6fb41..3c6fb41 100644 --- a/src/xmlfilewriter.cpp +++ b/src/old/xmlfilewriter.cpp | |||
diff --git a/src/xmlfilewriter.h b/src/old/xmlfilewriter.h index e328f96..e328f96 100644 --- a/src/xmlfilewriter.h +++ b/src/old/xmlfilewriter.h | |||
diff --git a/src/xmlnode.cpp b/src/old/xmlnode.cpp index b1ed9a9..96d5850 100644 --- a/src/xmlnode.cpp +++ b/src/old/xmlnode.cpp | |||
@@ -1,53 +1,15 @@ | |||
1 | #include "xmlnode.h" | 1 | #include "xmlnode.h" |
2 | #include "hashfunctionstring.h" | ||
3 | 2 | ||
4 | XmlNode::XmlNode( const char *sName, XmlNode *pParent, const char *sContent ) : | 3 | XmlNode::XmlNode( const Bu::FString &sName, XmlNode *pParent ) : |
5 | hProperties( new HashFunctionString(), 53, false ), | 4 | sName( sName ), |
6 | hChildren( new HashFunctionString(), 53, true ) | 5 | pParent( pParent ) |
7 | { | 6 | { |
8 | this->pParent = pParent; | ||
9 | if( sName != NULL ) | ||
10 | { | ||
11 | setName( sName ); | ||
12 | } | ||
13 | if( sContent != NULL ) | ||
14 | { | ||
15 | this->sPreContent = new std::string( sContent ); | ||
16 | } | ||
17 | else | ||
18 | { | ||
19 | this->sPreContent = NULL; | ||
20 | } | ||
21 | nCurContent = 0; | ||
22 | } | 7 | } |
23 | 8 | ||
24 | XmlNode::~XmlNode() | 9 | XmlNode::~XmlNode() |
25 | { | 10 | { |
26 | for( int j = 0; j < lChildren.getSize(); j++ ) | ||
27 | { | ||
28 | delete (XmlNode *)lChildren[j]; | ||
29 | } | ||
30 | for( int j = 0; j < lPropNames.getSize(); j++ ) | ||
31 | { | ||
32 | delete (std::string *)lPropNames[j]; | ||
33 | } | ||
34 | for( int j = 0; j < lPropValues.getSize(); j++ ) | ||
35 | { | ||
36 | delete (std::string *)lPropValues[j]; | ||
37 | } | ||
38 | for( int j = 0; j < lPostContent.getSize(); j++ ) | ||
39 | { | ||
40 | if( lPostContent[j] != NULL ) | ||
41 | { | ||
42 | delete (std::string *)lPostContent[j]; | ||
43 | } | ||
44 | } | ||
45 | if( sPreContent ) | ||
46 | { | ||
47 | delete sPreContent; | ||
48 | } | ||
49 | } | 11 | } |
50 | 12 | /* | |
51 | void XmlNode::setName( const char *sName ) | 13 | void XmlNode::setName( const char *sName ) |
52 | { | 14 | { |
53 | if( pParent ) | 15 | if( pParent ) |
@@ -120,18 +82,18 @@ const char *XmlNode::getContent( int nIndex ) | |||
120 | } | 82 | } |
121 | 83 | ||
122 | return NULL; | 84 | return NULL; |
123 | } | 85 | }*/ |
124 | 86 | ||
125 | XmlNode *XmlNode::addChild( const char *sName, const char *sContent ) | 87 | XmlNode *XmlNode::addChild( const Bu::FString &sName ) |
126 | { | 88 | { |
127 | return addChild( new XmlNode( sName, this, sContent ) ); | 89 | return addChild( new XmlNode( sName, this ) ); |
128 | } | 90 | } |
129 | 91 | ||
130 | XmlNode *XmlNode::addChild( XmlNode *pNode ) | 92 | XmlNode *XmlNode::addChild( XmlNode *pNode ) |
131 | { | 93 | { |
132 | lChildren.append( pNode ); | 94 | Child c = { typeNode }; |
133 | lPostContent.append( NULL ); | 95 | c.pNode = pNode; |
134 | nCurContent++; | 96 | lChildren.append( c ); |
135 | pNode->pParent = this; | 97 | pNode->pParent = this; |
136 | 98 | ||
137 | return pNode; | 99 | return pNode; |
@@ -142,21 +104,16 @@ XmlNode *XmlNode::getParent() | |||
142 | return pParent; | 104 | return pParent; |
143 | } | 105 | } |
144 | 106 | ||
145 | void XmlNode::addProperty( const char *sName, const char *sValue ) | 107 | void XmlNode::addProperty( const Bu::FString &sName, const Bu::FString &sValue ) |
146 | { | 108 | { |
147 | std::string *pName = new std::string( sName ); | 109 | hProperties.insert( sName, sValue ); |
148 | std::string *pValue = new std::string( sValue ); | ||
149 | |||
150 | hProperties.insert( pName->c_str(), pValue->c_str() ); | ||
151 | lPropNames.append( pName ); | ||
152 | lPropValues.append( pValue ); | ||
153 | } | 110 | } |
154 | 111 | ||
155 | int XmlNode::getNumProperties() | 112 | int XmlNode::getNumProperties() |
156 | { | 113 | { |
157 | return lPropNames.getSize(); | 114 | return hProperties.size(); |
158 | } | 115 | } |
159 | 116 | /* | |
160 | const char *XmlNode::getPropertyName( int nIndex ) | 117 | const char *XmlNode::getPropertyName( int nIndex ) |
161 | { | 118 | { |
162 | std::string *tmp = ((std::string *)lPropNames[nIndex]); | 119 | std::string *tmp = ((std::string *)lPropNames[nIndex]); |
@@ -172,15 +129,12 @@ const char *XmlNode::getProperty( int nIndex ) | |||
172 | return NULL; | 129 | return NULL; |
173 | return tmp->c_str(); | 130 | return tmp->c_str(); |
174 | } | 131 | } |
175 | 132 | */ | |
176 | const char *XmlNode::getProperty( const char *sName ) | 133 | Bu::FString XmlNode::getProperty( const Bu::FString &sName ) |
177 | { | 134 | { |
178 | const char *tmp = (const char *)hProperties[sName]; | 135 | return hProperties[sName]; |
179 | if( tmp == NULL ) | ||
180 | return NULL; | ||
181 | return tmp; | ||
182 | } | 136 | } |
183 | 137 | /* | |
184 | void XmlNode::deleteProperty( int nIndex ) | 138 | void XmlNode::deleteProperty( int nIndex ) |
185 | { | 139 | { |
186 | hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() ); | 140 | hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() ); |
@@ -194,29 +148,33 @@ void XmlNode::deleteProperty( int nIndex ) | |||
194 | 148 | ||
195 | bool XmlNode::hasChildren() | 149 | bool XmlNode::hasChildren() |
196 | { | 150 | { |
197 | return lChildren.getSize()>0; | 151 | return hChildren.getSize()>0; |
198 | } | 152 | }*/ |
199 | 153 | ||
200 | int XmlNode::getNumChildren() | 154 | int XmlNode::getNumChildren() |
201 | { | 155 | { |
202 | return lChildren.getSize(); | 156 | return lChildren.getSize(); |
203 | } | 157 | } |
204 | 158 | /* | |
205 | XmlNode *XmlNode::getChild( int nIndex ) | 159 | XmlNode *XmlNode::getChild( int nIndex ) |
206 | { | 160 | { |
207 | return (XmlNode *)lChildren[nIndex]; | 161 | return (XmlNode *)lChildren[nIndex]; |
208 | } | 162 | } |
209 | 163 | */ | |
210 | XmlNode *XmlNode::getChild( const char *sName, int nSkip ) | 164 | XmlNode *XmlNode::getChild( const Bu::FString &sName, int nSkip ) |
211 | { | 165 | { |
212 | return (XmlNode *)hChildren.get( sName, nSkip ); | 166 | if( !hChildren.has( sName ) ) |
167 | return NULL; | ||
168 | |||
169 | Bu::List<XmlNode *>::iterator i = hChildren[sName]->begin(); | ||
170 | return *i; | ||
213 | } | 171 | } |
214 | 172 | ||
215 | const char *XmlNode::getName() | 173 | Bu::FString XmlNode::getName() |
216 | { | 174 | { |
217 | return sName.c_str(); | 175 | return sName; |
218 | } | 176 | } |
219 | 177 | /* | |
220 | void XmlNode::deleteNode( int nIndex, const char *sReplacementText ) | 178 | void XmlNode::deleteNode( int nIndex, const char *sReplacementText ) |
221 | { | 179 | { |
222 | XmlNode *xRet = detatchNode( nIndex, sReplacementText ); | 180 | XmlNode *xRet = detatchNode( nIndex, sReplacementText ); |
@@ -442,4 +400,4 @@ void XmlNode::deleteNodeKeepChildren( int nIndex ) | |||
442 | void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ) | 400 | void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ) |
443 | { | 401 | { |
444 | } | 402 | } |
445 | 403 | */ | |
diff --git a/src/xmlnode.h b/src/old/xmlnode.h index 7525306..c895cd8 100644 --- a/src/xmlnode.h +++ b/src/old/xmlnode.h | |||
@@ -2,8 +2,9 @@ | |||
2 | #define XMLNODE | 2 | #define XMLNODE |
3 | 3 | ||
4 | #include <iostream> | 4 | #include <iostream> |
5 | #include "linkedlist.h" | 5 | #include "bu/list.h" |
6 | #include "hashtable.h" | 6 | #include "bu/hash.h" |
7 | #include "bu/fstring.h" | ||
7 | 8 | ||
8 | /** | 9 | /** |
9 | * Maintains all data pertient to an XML node, including sub-nodes and content. | 10 | * Maintains all data pertient to an XML node, including sub-nodes and content. |
@@ -25,9 +26,8 @@ public: | |||
25 | *@param sContent The initial content string. | 26 | *@param sContent The initial content string. |
26 | */ | 27 | */ |
27 | XmlNode( | 28 | XmlNode( |
28 | const char *sName=NULL, | 29 | const Bu::FString &sName, |
29 | XmlNode *pParent = NULL, | 30 | XmlNode *pParent=NULL |
30 | const char *sContent=NULL | ||
31 | ); | 31 | ); |
32 | 32 | ||
33 | /** | 33 | /** |
@@ -39,7 +39,7 @@ public: | |||
39 | * Change the name of the node. | 39 | * Change the name of the node. |
40 | *@param sName The new name of the node. | 40 | *@param sName The new name of the node. |
41 | */ | 41 | */ |
42 | void setName( const char *sName ); | 42 | //void setName( const char *sName ); |
43 | 43 | ||
44 | /** | 44 | /** |
45 | * Construct a new node and add it as a child to this node, also return a | 45 | * Construct a new node and add it as a child to this node, also return a |
@@ -48,7 +48,7 @@ public: | |||
48 | *@param sContent The initial content of the new node. | 48 | *@param sContent The initial content of the new node. |
49 | *@returns A pointer to the newly created child node. | 49 | *@returns A pointer to the newly created child node. |
50 | */ | 50 | */ |
51 | XmlNode *addChild( const char *sName, const char *sContent=NULL ); | 51 | XmlNode *addChild( const Bu::FString &sName ); |
52 | 52 | ||
53 | /** | 53 | /** |
54 | * Add an already created XmlNode as a child to this node. The new child | 54 | * Add an already created XmlNode as a child to this node. The new child |
@@ -65,7 +65,7 @@ public: | |||
65 | * in use will overwrite that property. | 65 | * in use will overwrite that property. |
66 | *@param sValue The textual value of the property. | 66 | *@param sValue The textual value of the property. |
67 | */ | 67 | */ |
68 | void addProperty( const char *sName, const char *sValue ); | 68 | void addProperty( const Bu::FString &sName, const Bu::FString &sValue ); |
69 | 69 | ||
70 | /** | 70 | /** |
71 | * Get a pointer to the parent node, if any. | 71 | * Get a pointer to the parent node, if any. |
@@ -86,14 +86,6 @@ public: | |||
86 | int getNumChildren(); | 86 | int getNumChildren(); |
87 | 87 | ||
88 | /** | 88 | /** |
89 | * Get a child node at a specific index. | ||
90 | *@param nIndex The zero-based index of the child to retreive. | ||
91 | *@returns A pointer to the child, or NULL if you requested an invalid | ||
92 | * index. | ||
93 | */ | ||
94 | XmlNode *getChild( int nIndex ); | ||
95 | |||
96 | /** | ||
97 | * Get a child with the specified name, and possibly skip value. For an | 89 | * Get a child with the specified name, and possibly skip value. For an |
98 | * explination of skip values see the HashTable. | 90 | * explination of skip values see the HashTable. |
99 | *@param sName The name of the child to find. | 91 | *@param sName The name of the child to find. |
@@ -101,14 +93,14 @@ public: | |||
101 | *@returns A pointer to the child, or NULL if no child with that name was | 93 | *@returns A pointer to the child, or NULL if no child with that name was |
102 | * found. | 94 | * found. |
103 | */ | 95 | */ |
104 | XmlNode *getChild( const char *sName, int nSkip=0 ); | 96 | XmlNode *getChild( const Bu::FString &sName, int nSkip=0 ); |
105 | 97 | ||
106 | /** | 98 | /** |
107 | * Get a pointer to the name of this node. Do not change this, use setName | 99 | * Get a pointer to the name of this node. Do not change this, use setName |
108 | * instead. | 100 | * instead. |
109 | *@returns A pointer to the name of this node. | 101 | *@returns A pointer to the name of this node. |
110 | */ | 102 | */ |
111 | const char *getName(); | 103 | Bu::FString getName(); |
112 | 104 | ||
113 | /** | 105 | /** |
114 | * Set the content of this node, optionally at a specific index. Using the | 106 | * Set the content of this node, optionally at a specific index. Using the |
@@ -116,14 +108,7 @@ public: | |||
116 | *@param sContent The content string to use. | 108 | *@param sContent The content string to use. |
117 | *@param nIndex The index of the content. | 109 | *@param nIndex The index of the content. |
118 | */ | 110 | */ |
119 | void setContent( const char *sContent, int nIndex=-1 ); | 111 | //void setContent( const char *sContent, int nIndex=-1 ); |
120 | |||
121 | /** | ||
122 | * Get the content string at a given index, or zero for initial content. | ||
123 | *@param nIndex The index of the content. | ||
124 | *@returns A pointer to the content at that location. | ||
125 | */ | ||
126 | const char *getContent( int nIndex = 0 ); | ||
127 | 112 | ||
128 | /** | 113 | /** |
129 | * Get the number of properties in this node. | 114 | * Get the number of properties in this node. |
@@ -132,36 +117,12 @@ public: | |||
132 | int getNumProperties(); | 117 | int getNumProperties(); |
133 | 118 | ||
134 | /** | 119 | /** |
135 | * Get a property's name by index. | ||
136 | *@param nIndex The index of the property to examine. | ||
137 | *@returns A pointer to the name of the property specified, or NULL if none | ||
138 | * found. | ||
139 | */ | ||
140 | const char *getPropertyName( int nIndex ); | ||
141 | |||
142 | /** | ||
143 | * Get a proprty's value by index. | ||
144 | *@param nIndex The index of the property to examine. | ||
145 | *@returns A pointer to the value of the property specified, or NULL if none | ||
146 | * found. | ||
147 | */ | ||
148 | const char *getProperty( int nIndex ); | ||
149 | |||
150 | /** | ||
151 | * Get a propery's value by name. | 120 | * Get a propery's value by name. |
152 | *@param sName The name of the property to examine. | 121 | *@param sName The name of the property to examine. |
153 | *@returns A pointer to the value of the property specified, or NULL if none | 122 | *@returns A pointer to the value of the property specified, or NULL if none |
154 | * found. | 123 | * found. |
155 | */ | 124 | */ |
156 | const char *getProperty( const char *sName ); | 125 | Bu::FString getProperty( const Bu::FString &sName ); |
157 | |||
158 | /** | ||
159 | * Delete a property by index. | ||
160 | *@param nIndex The index of the property to delete. | ||
161 | *@returns True if the property was found and deleted, false if it wasn't | ||
162 | * found. | ||
163 | */ | ||
164 | void deleteProperty( int nIndex ); | ||
165 | 126 | ||
166 | /** | 127 | /** |
167 | * Delete a child node, possibly replacing it with some text. This actually | 128 | * Delete a child node, possibly replacing it with some text. This actually |
@@ -171,7 +132,7 @@ public: | |||
171 | *@returns True of the node was found, and deleted, false if it wasn't | 132 | *@returns True of the node was found, and deleted, false if it wasn't |
172 | * found. | 133 | * found. |
173 | */ | 134 | */ |
174 | void deleteNode( int nIndex, const char *sReplacementText = NULL ); | 135 | //void deleteNode( int nIndex, const char *sReplacementText = NULL ); |
175 | 136 | ||
176 | /** | 137 | /** |
177 | * Delete a given node, but move all of it's children and content up to | 138 | * Delete a given node, but move all of it's children and content up to |
@@ -180,7 +141,7 @@ public: | |||
180 | *@param nIndex The node to delete. | 141 | *@param nIndex The node to delete. |
181 | *@returns True if the node was found and deleted, false if it wasn't. | 142 | *@returns True if the node was found and deleted, false if it wasn't. |
182 | */ | 143 | */ |
183 | void deleteNodeKeepChildren( int nIndex ); | 144 | //void deleteNodeKeepChildren( int nIndex ); |
184 | 145 | ||
185 | /** | 146 | /** |
186 | * Detatch a given child node from this node. This effectively works just | 147 | * Detatch a given child node from this node. This effectively works just |
@@ -192,7 +153,7 @@ public: | |||
192 | *@returns A pointer to the newly detatched node, which then passes | 153 | *@returns A pointer to the newly detatched node, which then passes |
193 | * ownership to the caller. | 154 | * ownership to the caller. |
194 | */ | 155 | */ |
195 | XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL ); | 156 | //XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL ); |
196 | 157 | ||
197 | /** | 158 | /** |
198 | * Replace a given node with a different node that is not currently owned by | 159 | * Replace a given node with a different node that is not currently owned by |
@@ -201,7 +162,7 @@ public: | |||
201 | *@param pNewNode The new node to replace the old node with. | 162 | *@param pNewNode The new node to replace the old node with. |
202 | *@returns True if the node was found and replaced, false if it wasn't. | 163 | *@returns True if the node was found and replaced, false if it wasn't. |
203 | */ | 164 | */ |
204 | void replaceNode( int nIndex, XmlNode *pNewNode ); | 165 | //void replaceNode( int nIndex, XmlNode *pNewNode ); |
205 | 166 | ||
206 | /** | 167 | /** |
207 | * Replace a given node with the children and content of a given node. | 168 | * Replace a given node with the children and content of a given node. |
@@ -210,24 +171,34 @@ public: | |||
210 | * replace the node specified by nIndex. | 171 | * replace the node specified by nIndex. |
211 | *@returns True if the node was found and replaced, false if it wasn't. | 172 | *@returns True if the node was found and replaced, false if it wasn't. |
212 | */ | 173 | */ |
213 | void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ); | 174 | //void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ); |
214 | 175 | ||
215 | /** | 176 | /** |
216 | * Get a copy of this node and all children. getCopy is recursive, so | 177 | * Get a copy of this node and all children. getCopy is recursive, so |
217 | * beware copying large trees of xml. | 178 | * beware copying large trees of xml. |
218 | *@returns A newly created copy of this node and all of it's children. | 179 | *@returns A newly created copy of this node and all of it's children. |
219 | */ | 180 | */ |
220 | XmlNode *getCopy(); | 181 | //XmlNode *getCopy(); |
182 | |||
183 | enum ChildType | ||
184 | { | ||
185 | typeNode, | ||
186 | typeContent | ||
187 | }; | ||
221 | 188 | ||
222 | private: | 189 | private: |
223 | std::string sName; /**< The name of the node. */ | 190 | typedef struct |
224 | std::string *sPreContent; /**< The content that goes before any node. */ | 191 | { |
225 | LinkedList lChildren; /**< The children. */ | 192 | uint8_t nType; |
226 | LinkedList lPostContent; /**< The content that comes after children. */ | 193 | union { |
227 | HashTable hProperties; /**< Property hashtable. */ | 194 | XmlNode *pNode; |
228 | HashTable hChildren; /**< Children hashtable. */ | 195 | Bu::FString *pContent; |
229 | LinkedList lPropNames; /**< List of property names. */ | 196 | }; |
230 | LinkedList lPropValues; /**< List of property values. */ | 197 | } Child; |
198 | Bu::FString sName; /**< The name of the node. */ | ||
199 | Bu::List<Child> lChildren; /**< The children. */ | ||
200 | Bu::Hash<Bu::FString, Bu::FString> hProperties; /**< Property hashtable. */ | ||
201 | Bu::Hash<Bu::FString, Bu::List<XmlNode *> > hChildren; /**< Children hashtable. */ | ||
231 | XmlNode *pParent; /**< A pointer to the parent of this node. */ | 202 | XmlNode *pParent; /**< A pointer to the parent of this node. */ |
232 | int nCurContent; /**< The current content we're on, for using the -1 on | 203 | int nCurContent; /**< The current content we're on, for using the -1 on |
233 | setContent. */ | 204 | setContent. */ |
diff --git a/src/xmlreader.cpp b/src/old/xmlreader.cpp index 18df69c..38cad5f 100644 --- a/src/xmlreader.cpp +++ b/src/old/xmlreader.cpp | |||
@@ -1,32 +1,49 @@ | |||
1 | #include "xmlreader.h" | 1 | #include "bu/xmlreader.h" |
2 | #include "exceptions.h" | 2 | #include "bu/exceptions.h" |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include "hashfunctionstring.h" | ||
5 | 4 | ||
6 | XmlReader::XmlReader( bool bStrip ) : | 5 | XmlReader::XmlReader( Bu::Stream &sIn, bool bStrip ) : |
7 | bStrip( bStrip ), | 6 | sIn( sIn ), |
8 | htEntity( new HashFunctionString(), 11 ) | 7 | bStrip( bStrip ) |
9 | { | 8 | { |
9 | buildDoc(); | ||
10 | } | 10 | } |
11 | 11 | ||
12 | XmlReader::~XmlReader() | 12 | XmlReader::~XmlReader() |
13 | { | 13 | { |
14 | void *i = htEntity.getFirstItemPos(); | 14 | } |
15 | while( (i = htEntity.getNextItemPos( i ) ) ) | 15 | |
16 | char XmlReader::getChar( int nIndex ) | ||
17 | { | ||
18 | if( sBuf.getSize() <= nIndex ) | ||
16 | { | 19 | { |
17 | free( (char *)(htEntity.getItemID( i )) ); | 20 | int nInc = nIndex-sBuf.getSize()+1; |
18 | delete (StaticString *)htEntity.getItemData( i ); | 21 | char *buf = new char[nInc]; |
22 | sIn.read( buf, nInc ); | ||
23 | sBuf.append( buf, nInc ); | ||
24 | delete[] buf; | ||
19 | } | 25 | } |
26 | |||
27 | return sBuf[nIndex]; | ||
20 | } | 28 | } |
21 | 29 | ||
22 | void XmlReader::addEntity( const char *name, const char *value ) | 30 | void XmlReader::usedChar( int nAmnt ) |
23 | { | 31 | { |
24 | if( htEntity[name] ) return; | 32 | if( nAmnt >= sBuf.getSize() ) |
25 | 33 | { | |
26 | char *sName = strdup( name ); | 34 | sBuf.clear(); |
27 | StaticString *sValue = new StaticString( value ); | 35 | } |
36 | else | ||
37 | { | ||
38 | char *s = sBuf.getStr(); | ||
39 | memcpy( s, s+nAmnt, sBuf.getSize()-nAmnt ); | ||
40 | sBuf.resize( sBuf.getSize()-nAmnt ); | ||
41 | } | ||
42 | } | ||
28 | 43 | ||
29 | htEntity.insert( sName, sValue ); | 44 | void XmlReader::addEntity( const Bu::FString &name, const Bu::FString &value ) |
45 | { | ||
46 | htEntity[name] = value; | ||
30 | } | 47 | } |
31 | 48 | ||
32 | #define gcall( x ) if( x == false ) return false; | 49 | #define gcall( x ) if( x == false ) return false; |
@@ -99,7 +116,7 @@ void XmlReader::entity() | |||
99 | { | 116 | { |
100 | usedChar( 2 ); | 117 | usedChar( 2 ); |
101 | ws(); | 118 | ws(); |
102 | std::string buf; | 119 | Bu::FString buf; |
103 | for(;;) | 120 | for(;;) |
104 | { | 121 | { |
105 | char chr = getChar(); | 122 | char chr = getChar(); |
@@ -111,7 +128,7 @@ void XmlReader::entity() | |||
111 | if( strcmp( buf.c_str(), "ENTITY") == 0 ) | 128 | if( strcmp( buf.c_str(), "ENTITY") == 0 ) |
112 | { | 129 | { |
113 | ws(); | 130 | ws(); |
114 | std::string name; | 131 | Bu::FString name; |
115 | for(;;) | 132 | for(;;) |
116 | { | 133 | { |
117 | char chr = getChar(); | 134 | char chr = getChar(); |
@@ -124,21 +141,19 @@ void XmlReader::entity() | |||
124 | usedChar(); | 141 | usedChar(); |
125 | if( quot != '\'' && quot != '\"' ) | 142 | if( quot != '\'' && quot != '\"' ) |
126 | { | 143 | { |
127 | throw XmlException( | 144 | throw Bu::XmlException( |
128 | "Only quoted entity values are supported." | 145 | "Only quoted entity values are supported." |
129 | ); | 146 | ); |
130 | } | 147 | } |
131 | std::string value; | 148 | Bu::FString value; |
132 | for(;;) | 149 | for(;;) |
133 | { | 150 | { |
134 | char chr = getChar(); | 151 | char chr = getChar(); |
135 | usedChar(); | 152 | usedChar(); |
136 | if( chr == '&' ) | 153 | if( chr == '&' ) |
137 | { | 154 | { |
138 | StaticString *tmp = getEscape(); | 155 | Bu::FString tmp = getEscape(); |
139 | if( tmp == NULL ) throw XmlException("Entity thing"); | 156 | value += tmp; |
140 | value += tmp->getString(); | ||
141 | delete tmp; | ||
142 | } | 157 | } |
143 | else if( chr == quot ) | 158 | else if( chr == quot ) |
144 | { | 159 | { |
@@ -158,7 +173,7 @@ void XmlReader::entity() | |||
158 | } | 173 | } |
159 | else | 174 | else |
160 | { | 175 | { |
161 | throw XmlException( | 176 | throw Bu::XmlException( |
162 | "Malformed ENTITY: unexpected '%c' found.", | 177 | "Malformed ENTITY: unexpected '%c' found.", |
163 | getChar() | 178 | getChar() |
164 | ); | 179 | ); |
@@ -166,7 +181,7 @@ void XmlReader::entity() | |||
166 | } | 181 | } |
167 | else | 182 | else |
168 | { | 183 | { |
169 | throw XmlException( | 184 | throw Bu::XmlException( |
170 | "Unsupported header symbol: %s", | 185 | "Unsupported header symbol: %s", |
171 | buf.c_str() | 186 | buf.c_str() |
172 | ); | 187 | ); |
@@ -203,12 +218,12 @@ bool XmlReader::node() | |||
203 | } | 218 | } |
204 | else | 219 | else |
205 | { | 220 | { |
206 | throw XmlException("Close node in singleNode malformed!"); | 221 | throw Bu::XmlException("Close node in singleNode malformed!"); |
207 | } | 222 | } |
208 | } | 223 | } |
209 | else | 224 | else |
210 | { | 225 | { |
211 | throw XmlException("Close node expected, but not found."); | 226 | throw Bu::XmlException("Close node expected, but not found."); |
212 | return false; | 227 | return false; |
213 | } | 228 | } |
214 | 229 | ||
@@ -224,7 +239,7 @@ bool XmlReader::startNode() | |||
224 | if( getChar() == '/' ) | 239 | if( getChar() == '/' ) |
225 | { | 240 | { |
226 | // Heh, it's actually a close node, go figure | 241 | // Heh, it's actually a close node, go figure |
227 | FlexBuf fbName; | 242 | Bu::FString sName; |
228 | usedChar(); | 243 | usedChar(); |
229 | gcall( ws() ); | 244 | gcall( ws() ); |
230 | 245 | ||
@@ -235,19 +250,19 @@ bool XmlReader::startNode() | |||
235 | { | 250 | { |
236 | // Here we actually compare the name we got to the name | 251 | // Here we actually compare the name we got to the name |
237 | // we already set, they have to match exactly. | 252 | // we already set, they have to match exactly. |
238 | if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) | 253 | if( getCurrent()->getName() == sName ) |
239 | { | 254 | { |
240 | closeNode(); | 255 | closeNode(); |
241 | break; | 256 | break; |
242 | } | 257 | } |
243 | else | 258 | else |
244 | { | 259 | { |
245 | throw XmlException("Got a mismatched node close tag."); | 260 | throw Bu::XmlException("Got a mismatched node close tag."); |
246 | } | 261 | } |
247 | } | 262 | } |
248 | else | 263 | else |
249 | { | 264 | { |
250 | fbName.appendData( chr ); | 265 | sName += chr; |
251 | usedChar(); | 266 | usedChar(); |
252 | } | 267 | } |
253 | } | 268 | } |
@@ -260,13 +275,13 @@ bool XmlReader::startNode() | |||
260 | } | 275 | } |
261 | else | 276 | else |
262 | { | 277 | { |
263 | throw XmlException("Got extra junk data instead of node close tag."); | 278 | throw Bu::XmlException("Got extra junk data instead of node close tag."); |
264 | } | 279 | } |
265 | } | 280 | } |
266 | else | 281 | else |
267 | { | 282 | { |
268 | // We're good, format is consistant | 283 | // We're good, format is consistant |
269 | addNode(); | 284 | //addNode(); |
270 | 285 | ||
271 | // Skip extra whitespace | 286 | // Skip extra whitespace |
272 | gcall( ws() ); | 287 | gcall( ws() ); |
@@ -278,7 +293,7 @@ bool XmlReader::startNode() | |||
278 | } | 293 | } |
279 | else | 294 | else |
280 | { | 295 | { |
281 | throw XmlException("Expected to find node opening char, '<'."); | 296 | throw Bu::XmlException("Expected to find node opening char, '<'."); |
282 | } | 297 | } |
283 | 298 | ||
284 | return true; | 299 | return true; |
@@ -286,19 +301,19 @@ bool XmlReader::startNode() | |||
286 | 301 | ||
287 | bool XmlReader::name() | 302 | bool XmlReader::name() |
288 | { | 303 | { |
289 | FlexBuf fbName; | 304 | Bu::FString sName; |
290 | 305 | ||
291 | while( true ) | 306 | while( true ) |
292 | { | 307 | { |
293 | char chr = getChar(); | 308 | char chr = getChar(); |
294 | if( isws( chr ) || chr == '>' || chr == '/' ) | 309 | if( isws( chr ) || chr == '>' || chr == '/' ) |
295 | { | 310 | { |
296 | setName( fbName.getData() ); | 311 | addNode( sName ); |
297 | return true; | 312 | return true; |
298 | } | 313 | } |
299 | else | 314 | else |
300 | { | 315 | { |
301 | fbName.appendData( chr ); | 316 | sName += chr; |
302 | usedChar(); | 317 | usedChar(); |
303 | } | 318 | } |
304 | } | 319 | } |
@@ -325,7 +340,7 @@ bool XmlReader::paramlist() | |||
325 | return true; | 340 | return true; |
326 | } | 341 | } |
327 | 342 | ||
328 | StaticString *XmlReader::getEscape() | 343 | Bu::FString XmlReader::getEscape() |
329 | { | 344 | { |
330 | if( getChar( 1 ) == '#' ) | 345 | if( getChar( 1 ) == '#' ) |
331 | { | 346 | { |
@@ -349,12 +364,12 @@ StaticString *XmlReader::getEscape() | |||
349 | buf[0] = (char)strtol( buf, (char **)NULL, base ); | 364 | buf[0] = (char)strtol( buf, (char **)NULL, base ); |
350 | buf[1] = '\0'; | 365 | buf[1] = '\0'; |
351 | 366 | ||
352 | return new StaticString( buf ); | 367 | return buf; |
353 | } | 368 | } |
354 | else | 369 | else |
355 | { | 370 | { |
356 | // ...otherwise replace with the appropriate string... | 371 | // ...otherwise replace with the appropriate string... |
357 | std::string buf; | 372 | Bu::FString buf; |
358 | usedChar(); | 373 | usedChar(); |
359 | for(;;) | 374 | for(;;) |
360 | { | 375 | { |
@@ -364,18 +379,14 @@ StaticString *XmlReader::getEscape() | |||
364 | buf += cbuf; | 379 | buf += cbuf; |
365 | } | 380 | } |
366 | 381 | ||
367 | StaticString *tmp = (StaticString *)htEntity[buf.c_str()]; | 382 | return htEntity[buf]; |
368 | if( tmp == NULL ) return NULL; | ||
369 | |||
370 | StaticString *ret = new StaticString( *tmp ); | ||
371 | return ret; | ||
372 | } | 383 | } |
373 | } | 384 | } |
374 | 385 | ||
375 | bool XmlReader::param() | 386 | bool XmlReader::param() |
376 | { | 387 | { |
377 | FlexBuf fbName; | 388 | Bu::FString sName; |
378 | FlexBuf fbValue; | 389 | Bu::FString sValue; |
379 | 390 | ||
380 | while( true ) | 391 | while( true ) |
381 | { | 392 | { |
@@ -386,7 +397,7 @@ bool XmlReader::param() | |||
386 | } | 397 | } |
387 | else | 398 | else |
388 | { | 399 | { |
389 | fbName.appendData( chr ); | 400 | sName.append( chr ); |
390 | usedChar(); | 401 | usedChar(); |
391 | } | 402 | } |
392 | } | 403 | } |
@@ -411,21 +422,18 @@ bool XmlReader::param() | |||
411 | if( chr == '"' ) | 422 | if( chr == '"' ) |
412 | { | 423 | { |
413 | usedChar(); | 424 | usedChar(); |
414 | addProperty( fbName.getData(), fbValue.getData() ); | 425 | addProperty( sName.getStr(), sValue.getStr() ); |
415 | return true; | 426 | return true; |
416 | } | 427 | } |
417 | else | 428 | else |
418 | { | 429 | { |
419 | if( chr == '&' ) | 430 | if( chr == '&' ) |
420 | { | 431 | { |
421 | StaticString *tmp = getEscape(); | 432 | sValue += getEscape(); |
422 | if( tmp == NULL ) return false; | ||
423 | fbValue.appendData( tmp->getString() ); | ||
424 | delete tmp; | ||
425 | } | 433 | } |
426 | else | 434 | else |
427 | { | 435 | { |
428 | fbValue.appendData( chr ); | 436 | sValue += chr; |
429 | usedChar(); | 437 | usedChar(); |
430 | } | 438 | } |
431 | } | 439 | } |
@@ -439,21 +447,18 @@ bool XmlReader::param() | |||
439 | chr = getChar(); | 447 | chr = getChar(); |
440 | if( isws( chr ) || chr == '/' || chr == '>' ) | 448 | if( isws( chr ) || chr == '/' || chr == '>' ) |
441 | { | 449 | { |
442 | addProperty( fbName.getData(), fbValue.getData() ); | 450 | addProperty( sName.getStr(), sValue.getStr() ); |
443 | return true; | 451 | return true; |
444 | } | 452 | } |
445 | else | 453 | else |
446 | { | 454 | { |
447 | if( chr == '&' ) | 455 | if( chr == '&' ) |
448 | { | 456 | { |
449 | StaticString *tmp = getEscape(); | 457 | sValue += getEscape(); |
450 | if( tmp == NULL ) return false; | ||
451 | fbValue.appendData( tmp->getString() ); | ||
452 | delete tmp; | ||
453 | } | 458 | } |
454 | else | 459 | else |
455 | { | 460 | { |
456 | fbValue.appendData( chr ); | 461 | sValue += chr; |
457 | usedChar(); | 462 | usedChar(); |
458 | } | 463 | } |
459 | } | 464 | } |
@@ -462,7 +467,7 @@ bool XmlReader::param() | |||
462 | } | 467 | } |
463 | else | 468 | else |
464 | { | 469 | { |
465 | throw XmlException("Expected an equals to seperate the params."); | 470 | throw Bu::XmlException("Expected an equals to seperate the params."); |
466 | return false; | 471 | return false; |
467 | } | 472 | } |
468 | 473 | ||
@@ -471,7 +476,7 @@ bool XmlReader::param() | |||
471 | 476 | ||
472 | bool XmlReader::content() | 477 | bool XmlReader::content() |
473 | { | 478 | { |
474 | FlexBuf fbContent; | 479 | Bu::FString sContent; |
475 | 480 | ||
476 | if( bStrip ) gcall( ws() ); | 481 | if( bStrip ) gcall( ws() ); |
477 | 482 | ||
@@ -482,37 +487,37 @@ bool XmlReader::content() | |||
482 | { | 487 | { |
483 | if( getChar(1) == '/' ) | 488 | if( getChar(1) == '/' ) |
484 | { | 489 | { |
485 | if( fbContent.getLength() > 0 ) | 490 | if( sContent.getSize() > 0 ) |
486 | { | 491 | { |
487 | if( bStrip ) | 492 | if( bStrip ) |
488 | { | 493 | { |
489 | int j; | 494 | int j; |
490 | for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); | 495 | for( j = sContent.getSize()-1; isws(sContent[j]); j-- ); |
491 | ((char *)fbContent.getData())[j+1] = '\0'; | 496 | sContent[j+1] = '\0'; |
492 | } | 497 | } |
493 | setContent( fbContent.getData() ); | 498 | setContent( sContent.getStr() ); |
494 | } | 499 | } |
495 | usedChar( 2 ); | 500 | usedChar( 2 ); |
496 | gcall( ws() ); | 501 | gcall( ws() ); |
497 | FlexBuf fbName; | 502 | Bu::FString sName; |
498 | while( true ) | 503 | while( true ) |
499 | { | 504 | { |
500 | chr = getChar(); | 505 | chr = getChar(); |
501 | if( isws( chr ) || chr == '>' ) | 506 | if( isws( chr ) || chr == '>' ) |
502 | { | 507 | { |
503 | if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) | 508 | if( !strcasecmp( getCurrent()->getName().getStr(), sName.getStr() ) ) |
504 | { | 509 | { |
505 | closeNode(); | 510 | closeNode(); |
506 | break; | 511 | break; |
507 | } | 512 | } |
508 | else | 513 | else |
509 | { | 514 | { |
510 | throw XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName(), fbName.getData() ); | 515 | throw Bu::XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName().getStr(), sName.getStr() ); |
511 | } | 516 | } |
512 | } | 517 | } |
513 | else | 518 | else |
514 | { | 519 | { |
515 | fbName.appendData( chr ); | 520 | sName += chr; |
516 | usedChar(); | 521 | usedChar(); |
517 | } | 522 | } |
518 | } | 523 | } |
@@ -524,7 +529,7 @@ bool XmlReader::content() | |||
524 | } | 529 | } |
525 | else | 530 | else |
526 | { | 531 | { |
527 | throw XmlException("Malformed close tag."); | 532 | throw Bu::XmlException("Malformed close tag."); |
528 | } | 533 | } |
529 | } | 534 | } |
530 | else if( getChar(1) == '!' ) | 535 | else if( getChar(1) == '!' ) |
@@ -534,7 +539,7 @@ bool XmlReader::content() | |||
534 | getChar(3) != '-' ) | 539 | getChar(3) != '-' ) |
535 | { | 540 | { |
536 | // Not a valid XML comment | 541 | // Not a valid XML comment |
537 | throw XmlException("Malformed comment start tag found."); | 542 | throw Bu::XmlException("Malformed comment start tag found."); |
538 | } | 543 | } |
539 | 544 | ||
540 | usedChar( 4 ); | 545 | usedChar( 4 ); |
@@ -549,7 +554,7 @@ bool XmlReader::content() | |||
549 | // The next one has to be a '>' now | 554 | // The next one has to be a '>' now |
550 | if( getChar( 2 ) != '>' ) | 555 | if( getChar( 2 ) != '>' ) |
551 | { | 556 | { |
552 | throw XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment."); | 557 | throw Bu::XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment."); |
553 | } | 558 | } |
554 | usedChar( 3 ); | 559 | usedChar( 3 ); |
555 | break; | 560 | break; |
@@ -569,16 +574,16 @@ bool XmlReader::content() | |||
569 | } | 574 | } |
570 | else | 575 | else |
571 | { | 576 | { |
572 | if( fbContent.getLength() > 0 ) | 577 | if( sContent.getSize() > 0 ) |
573 | { | 578 | { |
574 | if( bStrip ) | 579 | if( bStrip ) |
575 | { | 580 | { |
576 | int j; | 581 | int j; |
577 | for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); | 582 | for( j = sContent.getSize()-1; isws(sContent[j]); j-- ); |
578 | ((char *)fbContent.getData())[j+1] = '\0'; | 583 | sContent[j+1] = '\0'; |
579 | } | 584 | } |
580 | setContent( fbContent.getData() ); | 585 | setContent( sContent.getStr() ); |
581 | fbContent.clearData(); | 586 | sContent.clear(); |
582 | } | 587 | } |
583 | gcall( node() ); | 588 | gcall( node() ); |
584 | } | 589 | } |
@@ -587,14 +592,11 @@ bool XmlReader::content() | |||
587 | } | 592 | } |
588 | else if( chr == '&' ) | 593 | else if( chr == '&' ) |
589 | { | 594 | { |
590 | StaticString *tmp = getEscape(); | 595 | sContent += getEscape(); |
591 | if( tmp == NULL ) return false; | ||
592 | fbContent.appendData( tmp->getString() ); | ||
593 | delete tmp; | ||
594 | } | 596 | } |
595 | else | 597 | else |
596 | { | 598 | { |
597 | fbContent.appendData( chr ); | 599 | sContent += chr; |
598 | usedChar(); | 600 | usedChar(); |
599 | } | 601 | } |
600 | } | 602 | } |
diff --git a/src/xmlreader.h b/src/old/xmlreader.h index c8f7202..7c85ddb 100644 --- a/src/xmlreader.h +++ b/src/old/xmlreader.h | |||
@@ -2,10 +2,10 @@ | |||
2 | #define XMLREADER | 2 | #define XMLREADER |
3 | 3 | ||
4 | #include <stdio.h> | 4 | #include <stdio.h> |
5 | #include "xmldocument.h" | 5 | #include "bu/xmldocument.h" |
6 | #include "flexbuf.h" | 6 | #include "bu/hash.h" |
7 | #include "hashtable.h" | 7 | #include "bu/fstring.h" |
8 | #include "staticstring.h" | 8 | #include "bu/stream.h" |
9 | 9 | ||
10 | /** | 10 | /** |
11 | * Takes care of reading in xml formatted data from a file. This could/should | 11 | * Takes care of reading in xml formatted data from a file. This could/should |
@@ -32,7 +32,7 @@ public: | |||
32 | * in content, a-la html. | 32 | * in content, a-la html. |
33 | *@param bStrip Strip out leading and trailing whitespace? | 33 | *@param bStrip Strip out leading and trailing whitespace? |
34 | */ | 34 | */ |
35 | XmlReader( bool bStrip=false ); | 35 | XmlReader( Bu::Stream &sIn, bool bStrip=false ); |
36 | 36 | ||
37 | /** | 37 | /** |
38 | * Destroy this XmlReader. | 38 | * Destroy this XmlReader. |
@@ -54,12 +54,12 @@ private: | |||
54 | *@returns A single character at the requested position, or 0 for end of | 54 | *@returns A single character at the requested position, or 0 for end of |
55 | * stream. | 55 | * stream. |
56 | */ | 56 | */ |
57 | virtual char getChar( int nIndex = 0 ) = 0; | 57 | virtual char getChar( int nIndex = 0 ); |
58 | 58 | ||
59 | /** | 59 | /** |
60 | * Called to increment the current stream position by a single character. | 60 | * Called to increment the current stream position by a single character. |
61 | */ | 61 | */ |
62 | virtual void usedChar( int nAmnt = 1) = 0; | 62 | virtual void usedChar( int nAmnt = 1 ); |
63 | 63 | ||
64 | /** | 64 | /** |
65 | * Automoton function: is whitespace. | 65 | * Automoton function: is whitespace. |
@@ -108,9 +108,9 @@ private: | |||
108 | *@param name The name of the entity | 108 | *@param name The name of the entity |
109 | *@param value The value of the entity | 109 | *@param value The value of the entity |
110 | */ | 110 | */ |
111 | void addEntity( const char *name, const char *value ); | 111 | void addEntity( const Bu::FString &name, const Bu::FString &value ); |
112 | 112 | ||
113 | StaticString *getEscape(); | 113 | Bu::FString getEscape(); |
114 | 114 | ||
115 | /** | 115 | /** |
116 | * Automoton function: paramlist. Processes a list of node params. | 116 | * Automoton function: paramlist. Processes a list of node params. |
@@ -130,12 +130,15 @@ private: | |||
130 | */ | 130 | */ |
131 | bool content(); | 131 | bool content(); |
132 | 132 | ||
133 | FlexBuf fbContent; /**< buffer for the current node's content. */ | 133 | Bu::FString sContent; /**< buffer for the current node's content. */ |
134 | FlexBuf fbParamName; /**< buffer for the current param's name. */ | 134 | Bu::FString sParamName; /**< buffer for the current param's name. */ |
135 | FlexBuf fbParamValue; /**< buffer for the current param's value. */ | 135 | Bu::FString sParamValue; /**< buffer for the current param's value. */ |
136 | bool bStrip; /**< Are we stripping whitespace? */ | 136 | Bu::Stream &sIn; |
137 | bool bStrip; /**< Are we stripping whitespace? */ | ||
137 | 138 | ||
138 | HashTable htEntity; /**< Entity type definitions. */ | 139 | Bu::Hash<Bu::FString,Bu::FString> htEntity; /**< Entity type definitions. */ |
140 | |||
141 | Bu::FString sBuf; | ||
139 | }; | 142 | }; |
140 | 143 | ||
141 | #endif | 144 | #endif |
diff --git a/src/xmlstringreader.cpp b/src/old/xmlstringreader.cpp index 3956ff3..3956ff3 100644 --- a/src/xmlstringreader.cpp +++ b/src/old/xmlstringreader.cpp | |||
diff --git a/src/xmlstringreader.h b/src/old/xmlstringreader.h index 1239ef4..1239ef4 100644 --- a/src/xmlstringreader.h +++ b/src/old/xmlstringreader.h | |||
diff --git a/src/xmlstringwriter.cpp b/src/old/xmlstringwriter.cpp index adeed6a..adeed6a 100644 --- a/src/xmlstringwriter.cpp +++ b/src/old/xmlstringwriter.cpp | |||
diff --git a/src/xmlstringwriter.h b/src/old/xmlstringwriter.h index 0d567b9..0d567b9 100644 --- a/src/xmlstringwriter.h +++ b/src/old/xmlstringwriter.h | |||
diff --git a/src/xmlwriter.cpp b/src/old/xmlwriter.cpp index 56880b6..7dc6ca9 100644 --- a/src/xmlwriter.cpp +++ b/src/old/xmlwriter.cpp | |||
@@ -2,17 +2,10 @@ | |||
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include "xmlwriter.h" | 3 | #include "xmlwriter.h" |
4 | 4 | ||
5 | XmlWriter::XmlWriter( const char *sIndent, XmlNode *pRoot ) : | 5 | XmlWriter::XmlWriter( const Bu::FString &sIndent, XmlNode *pRoot ) : |
6 | XmlDocument( pRoot ) | 6 | XmlDocument( pRoot ), |
7 | sIndent( sIndent ) | ||
7 | { | 8 | { |
8 | if( sIndent == NULL ) | ||
9 | { | ||
10 | this->sIndent = ""; | ||
11 | } | ||
12 | else | ||
13 | { | ||
14 | this->sIndent = sIndent; | ||
15 | } | ||
16 | } | 9 | } |
17 | 10 | ||
18 | XmlWriter::~XmlWriter() | 11 | XmlWriter::~XmlWriter() |
@@ -24,7 +17,7 @@ void XmlWriter::write() | |||
24 | write( getRoot(), sIndent.c_str() ); | 17 | write( getRoot(), sIndent.c_str() ); |
25 | } | 18 | } |
26 | 19 | ||
27 | void XmlWriter::write( XmlNode *pRoot, const char *sIndent ) | 20 | void XmlWriter::write( XmlNode *pRoot, const Bu::FString &sIndent ) |
28 | { | 21 | { |
29 | writeNode( pRoot, 0, sIndent ); | 22 | writeNode( pRoot, 0, sIndent ); |
30 | } | 23 | } |
@@ -39,7 +32,7 @@ void XmlWriter::closeNode() | |||
39 | } | 32 | } |
40 | } | 33 | } |
41 | 34 | ||
42 | void XmlWriter::writeIndent( int nIndent, const char *sIndent ) | 35 | void XmlWriter::writeIndent( int nIndent, const Bu::FString &sIndent ) |
43 | { | 36 | { |
44 | if( sIndent == NULL ) return; | 37 | if( sIndent == NULL ) return; |
45 | for( int j = 0; j < nIndent; j++ ) | 38 | for( int j = 0; j < nIndent; j++ ) |
@@ -48,26 +41,27 @@ void XmlWriter::writeIndent( int nIndent, const char *sIndent ) | |||
48 | } | 41 | } |
49 | } | 42 | } |
50 | 43 | ||
51 | std::string XmlWriter::escape( std::string sIn ) | 44 | Bu::FString XmlWriter::escape( const Bu::FString &sIn ) |
52 | { | 45 | { |
53 | std::string sOut; | 46 | Bu::FString sOut; |
54 | 47 | ||
55 | std::string::const_iterator i; | 48 | int nMax = sIn.getSize(); |
56 | for( i = sIn.begin(); i != sIn.end(); i++ ) | 49 | for( int j = 0; j < nMax; j++ ) |
57 | { | 50 | { |
58 | if( ((*i >= ' ' && *i <= '9') || | 51 | char c = sIn[j]; |
59 | (*i >= 'a' && *i <= 'z') || | 52 | if( ((c >= ' ' && c <= '9') || |
60 | (*i >= 'A' && *i <= 'Z') ) && | 53 | (c >= 'a' && c <= 'z') || |
61 | (*i != '\"' && *i != '\'' && *i != '&') | 54 | (c >= 'A' && c <= 'Z') ) && |
55 | (c != '\"' && c != '\'' && c != '&') | ||
62 | ) | 56 | ) |
63 | { | 57 | { |
64 | sOut += *i; | 58 | sOut += c; |
65 | } | 59 | } |
66 | else | 60 | else |
67 | { | 61 | { |
68 | sOut += "&#"; | 62 | sOut += "&#"; |
69 | char buf[4]; | 63 | char buf[4]; |
70 | sprintf( buf, "%u", (unsigned char)*i ); | 64 | sprintf( buf, "%u", (unsigned char)c ); |
71 | sOut += buf; | 65 | sOut += buf; |
72 | sOut += ';'; | 66 | sOut += ';'; |
73 | } | 67 | } |
@@ -76,19 +70,19 @@ std::string XmlWriter::escape( std::string sIn ) | |||
76 | return sOut; | 70 | return sOut; |
77 | } | 71 | } |
78 | 72 | ||
79 | void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ) | 73 | void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent ) |
80 | { | 74 | { |
81 | for( int j = 0; j < pNode->getNumProperties(); j++ ) | 75 | for( int j = 0; j < pNode->getNumProperties(); j++ ) |
82 | { | 76 | { |
83 | writeString(" "); | 77 | writeString(" "); |
84 | writeString( pNode->getPropertyName( j ) ); | 78 | //writeString( pNode->getPropertyName( j ) ); |
85 | writeString("=\""); | 79 | writeString("=\""); |
86 | writeString( escape( pNode->getProperty( j ) ).c_str() ); | 80 | //writeString( escape( pNode->getProperty( j ) ).c_str() ); |
87 | writeString("\""); | 81 | writeString("\""); |
88 | } | 82 | } |
89 | } | 83 | } |
90 | 84 | ||
91 | void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) | 85 | void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent ) |
92 | { | 86 | { |
93 | if( pNode->hasChildren() ) | 87 | if( pNode->hasChildren() ) |
94 | { | 88 | { |
@@ -96,15 +90,15 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) | |||
96 | writeString("<"); | 90 | writeString("<"); |
97 | writeString( pNode->getName() ); | 91 | writeString( pNode->getName() ); |
98 | writeNodeProps( pNode, nIndent, sIndent ); | 92 | writeNodeProps( pNode, nIndent, sIndent ); |
99 | if( sIndent ) | 93 | if( sIndent != "" ) |
100 | writeString(">\n"); | 94 | writeString(">\n"); |
101 | else | 95 | else |
102 | writeString(">"); | 96 | writeString(">"); |
103 | 97 | /* | |
104 | if( pNode->getContent( 0 ) ) | 98 | if( pNode->getContent( 0 ) ) |
105 | { | 99 | { |
106 | writeIndent( nIndent+1, sIndent ); | 100 | writeIndent( nIndent+1, sIndent ); |
107 | if( sIndent ) | 101 | if( sIndent != "" ) |
108 | { | 102 | { |
109 | writeString( pNode->getContent( 0 ) ); | 103 | writeString( pNode->getContent( 0 ) ); |
110 | writeString("\n"); | 104 | writeString("\n"); |
@@ -129,9 +123,9 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) | |||
129 | writeString( pNode->getContent( j+1 ) ); | 123 | writeString( pNode->getContent( j+1 ) ); |
130 | } | 124 | } |
131 | } | 125 | } |
132 | 126 | */ | |
133 | writeIndent( nIndent, sIndent ); | 127 | writeIndent( nIndent, sIndent ); |
134 | if( sIndent ) | 128 | if( sIndent != "" ) |
135 | { | 129 | { |
136 | writeString("</"); | 130 | writeString("</"); |
137 | writeString( pNode->getName() ); | 131 | writeString( pNode->getName() ); |
@@ -143,7 +137,7 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) | |||
143 | writeString( pNode->getName() ); | 137 | writeString( pNode->getName() ); |
144 | writeString(">"); | 138 | writeString(">"); |
145 | } | 139 | } |
146 | } | 140 | }/* |
147 | else if( pNode->getContent() ) | 141 | else if( pNode->getContent() ) |
148 | { | 142 | { |
149 | writeIndent( nIndent, sIndent ); | 143 | writeIndent( nIndent, sIndent ); |
@@ -157,14 +151,14 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) | |||
157 | writeString(">"); | 151 | writeString(">"); |
158 | if( sIndent ) | 152 | if( sIndent ) |
159 | writeString("\n"); | 153 | writeString("\n"); |
160 | } | 154 | }*/ |
161 | else | 155 | else |
162 | { | 156 | { |
163 | writeIndent( nIndent, sIndent ); | 157 | writeIndent( nIndent, sIndent ); |
164 | writeString("<"); | 158 | writeString("<"); |
165 | writeString( pNode->getName() ); | 159 | writeString( pNode->getName() ); |
166 | writeNodeProps( pNode, nIndent, sIndent ); | 160 | writeNodeProps( pNode, nIndent, sIndent ); |
167 | if( sIndent ) | 161 | if( sIndent != "" ) |
168 | writeString("/>\n"); | 162 | writeString("/>\n"); |
169 | else | 163 | else |
170 | writeString("/>"); | 164 | writeString("/>"); |
diff --git a/src/xmlwriter.h b/src/old/xmlwriter.h index c48e810..7e3c876 100644 --- a/src/xmlwriter.h +++ b/src/old/xmlwriter.h | |||
@@ -31,7 +31,7 @@ public: | |||
31 | * this to a tab or some spaces it will never effect the content of your | 31 | * this to a tab or some spaces it will never effect the content of your |
32 | * file. | 32 | * file. |
33 | */ | 33 | */ |
34 | XmlWriter( const char *sIndent=NULL, XmlNode *pRoot=NULL ); | 34 | XmlWriter( const Bu::FString &sIndent="", XmlNode *pRoot=NULL ); |
35 | 35 | ||
36 | /** | 36 | /** |
37 | * Destroy the writer. | 37 | * Destroy the writer. |
@@ -49,16 +49,16 @@ public: | |||
49 | void write(); | 49 | void write(); |
50 | 50 | ||
51 | private: | 51 | private: |
52 | std::string sIndent; /**< The indent string */ | 52 | Bu::FString sIndent; /**< The indent string */ |
53 | 53 | ||
54 | std::string escape( std::string sIn ); | 54 | Bu::FString escape( const Bu::FString &sIn ); |
55 | 55 | ||
56 | /** | 56 | /** |
57 | * Write the file. | 57 | * Write the file. |
58 | *@param pNode The root node | 58 | *@param pNode The root node |
59 | *@param sIndent The indent text. | 59 | *@param sIndent The indent text. |
60 | */ | 60 | */ |
61 | void write( XmlNode *pNode, const char *sIndent=NULL ); | 61 | void write( XmlNode *pNode, const Bu::FString &sIndent ); |
62 | 62 | ||
63 | /** | 63 | /** |
64 | * Write a node in the file, including children. | 64 | * Write a node in the file, including children. |
@@ -66,7 +66,7 @@ private: | |||
66 | *@param nIndent The indent level (the number of times to include sIndent) | 66 | *@param nIndent The indent level (the number of times to include sIndent) |
67 | *@param sIndent The indent text. | 67 | *@param sIndent The indent text. |
68 | */ | 68 | */ |
69 | void writeNode( XmlNode *pNode, int nIndent, const char *sIndent ); | 69 | void writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent ); |
70 | 70 | ||
71 | /** | 71 | /** |
72 | * Write the properties of a node. | 72 | * Write the properties of a node. |
@@ -74,14 +74,14 @@ private: | |||
74 | *@param nIndent The indent level of the containing node | 74 | *@param nIndent The indent level of the containing node |
75 | *@param sIndent The indent text. | 75 | *@param sIndent The indent text. |
76 | */ | 76 | */ |
77 | void writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ); | 77 | void writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent ); |
78 | 78 | ||
79 | /** | 79 | /** |
80 | * Called to write the actual indent. | 80 | * Called to write the actual indent. |
81 | *@param nIndent The indent level. | 81 | *@param nIndent The indent level. |
82 | *@param sIndent The indent text. | 82 | *@param sIndent The indent text. |
83 | */ | 83 | */ |
84 | void writeIndent( int nIndent, const char *sIndent ); | 84 | void writeIndent( int nIndent, const Bu::FString &sIndent ); |
85 | 85 | ||
86 | /** | 86 | /** |
87 | * This is the function that must be overridden in order to use this class. | 87 | * This is the function that must be overridden in order to use this class. |
@@ -90,7 +90,7 @@ private: | |||
90 | * will break the XML formatting. | 90 | * will break the XML formatting. |
91 | *@param sString The string data to write to the output. | 91 | *@param sString The string data to write to the output. |
92 | */ | 92 | */ |
93 | virtual void writeString( const char *sString ) = 0; | 93 | virtual void writeString( const Bu::FString &sString ) = 0; |
94 | }; | 94 | }; |
95 | 95 | ||
96 | #endif | 96 | #endif |
diff --git a/src/paramproc.cpp b/src/paramproc.cpp index a352e66..34e973e 100644 --- a/src/paramproc.cpp +++ b/src/paramproc.cpp | |||
@@ -2,10 +2,10 @@ | |||
2 | #include <stdio.h> | 2 | #include <stdio.h> |
3 | 3 | ||
4 | #define ptrtype( iitype, iiname ) \ | 4 | #define ptrtype( iitype, iiname ) \ |
5 | ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ | 5 | Bu::ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ |
6 | type( vt ##iiname ) { val.iiname = iiname; } | 6 | type( vt ##iiname ) { val.iiname = iiname; } |
7 | 7 | ||
8 | ParamProc::ParamPtr::ParamPtr() | 8 | Bu::ParamProc::ParamPtr::ParamPtr() |
9 | { | 9 | { |
10 | val.str = NULL; | 10 | val.str = NULL; |
11 | type = vtunset; | 11 | type = vtunset; |
@@ -25,7 +25,7 @@ ptrtype( double, float64 ); | |||
25 | ptrtype( long double, float96 ); | 25 | ptrtype( long double, float96 ); |
26 | ptrtype( bool, bln ); | 26 | ptrtype( bool, bln ); |
27 | 27 | ||
28 | ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) | 28 | Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) |
29 | { | 29 | { |
30 | val = ptr.val; | 30 | val = ptr.val; |
31 | type = ptr.type; | 31 | type = ptr.type; |
@@ -33,12 +33,12 @@ ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) | |||
33 | return *this; | 33 | return *this; |
34 | } | 34 | } |
35 | 35 | ||
36 | bool ParamProc::ParamPtr::isSet() | 36 | bool Bu::ParamProc::ParamPtr::isSet() |
37 | { | 37 | { |
38 | return type != vtunset; | 38 | return type != vtunset; |
39 | } | 39 | } |
40 | 40 | ||
41 | ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( const char *str ) | 41 | Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( const char *str ) |
42 | { | 42 | { |
43 | if( !isSet() ) return *this; | 43 | if( !isSet() ) return *this; |
44 | switch( type ) | 44 | switch( type ) |
@@ -107,11 +107,11 @@ ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( const char *str ) | |||
107 | return *this; | 107 | return *this; |
108 | } | 108 | } |
109 | 109 | ||
110 | ParamProc::ParamProc() | 110 | Bu::ParamProc::ParamProc() |
111 | { | 111 | { |
112 | } | 112 | } |
113 | 113 | ||
114 | ParamProc::~ParamProc() | 114 | Bu::ParamProc::~ParamProc() |
115 | { | 115 | { |
116 | for( std::list<ArgSpec *>::iterator i = lArg.begin(); | 116 | for( std::list<ArgSpec *>::iterator i = lArg.begin(); |
117 | i != lArg.end(); i++ ) | 117 | i != lArg.end(); i++ ) |
@@ -127,14 +127,14 @@ ParamProc::~ParamProc() | |||
127 | 127 | ||
128 | } | 128 | } |
129 | /* | 129 | /* |
130 | void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) | 130 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) |
131 | { | 131 | { |
132 | printf("Calling callback...\n"); | 132 | printf("Calling callback...\n"); |
133 | val = "Hello there, this is set in the ParamProc"; | 133 | val = "Hello there, this is set in the ParamProc"; |
134 | (this->*proc)(); | 134 | (this->*proc)(); |
135 | }*/ | 135 | }*/ |
136 | 136 | ||
137 | void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, | 137 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, |
138 | ParamPtr val, const char *lpDesc, const char *lpExtra, | 138 | ParamPtr val, const char *lpDesc, const char *lpExtra, |
139 | const char *lpValue ) | 139 | const char *lpValue ) |
140 | { | 140 | { |
@@ -161,63 +161,63 @@ void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, | |||
161 | } | 161 | } |
162 | } | 162 | } |
163 | 163 | ||
164 | void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, | 164 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, |
165 | const char *lpDesc, const char *lpExtra, | 165 | const char *lpDesc, const char *lpExtra, |
166 | const char *lpValue ) | 166 | const char *lpValue ) |
167 | { | 167 | { |
168 | addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); | 168 | addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); |
169 | } | 169 | } |
170 | 170 | ||
171 | void ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, | 171 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, |
172 | const char *lpDesc, const char *lpExtra, | 172 | const char *lpDesc, const char *lpExtra, |
173 | const char *lpValue ) | 173 | const char *lpValue ) |
174 | { | 174 | { |
175 | addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); | 175 | addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); |
176 | } | 176 | } |
177 | 177 | ||
178 | void ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, | 178 | void Bu::ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, |
179 | const char *lpDesc, const char *lpExtra, | 179 | const char *lpDesc, const char *lpExtra, |
180 | const char *lpValue ) | 180 | const char *lpValue ) |
181 | { | 181 | { |
182 | addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); | 182 | addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); |
183 | } | 183 | } |
184 | 184 | ||
185 | void ParamProc::addParam( const char *lpWord, Proc proc, | 185 | void Bu::ParamProc::addParam( const char *lpWord, Proc proc, |
186 | const char *lpDesc, const char *lpExtra, | 186 | const char *lpDesc, const char *lpExtra, |
187 | const char *lpValue ) | 187 | const char *lpValue ) |
188 | { | 188 | { |
189 | addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); | 189 | addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); |
190 | } | 190 | } |
191 | 191 | ||
192 | void ParamProc::addParam( const char *lpWord, ParamPtr val, | 192 | void Bu::ParamProc::addParam( const char *lpWord, ParamPtr val, |
193 | const char *lpDesc, const char *lpExtra, | 193 | const char *lpDesc, const char *lpExtra, |
194 | const char *lpValue ) | 194 | const char *lpValue ) |
195 | { | 195 | { |
196 | addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); | 196 | addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); |
197 | } | 197 | } |
198 | 198 | ||
199 | void ParamProc::addParam( char cChar, Proc proc, ParamPtr val, | 199 | void Bu::ParamProc::addParam( char cChar, Proc proc, ParamPtr val, |
200 | const char *lpDesc, const char *lpExtra, | 200 | const char *lpDesc, const char *lpExtra, |
201 | const char *lpValue ) | 201 | const char *lpValue ) |
202 | { | 202 | { |
203 | addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); | 203 | addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); |
204 | } | 204 | } |
205 | 205 | ||
206 | void ParamProc::addParam( char cChar, Proc proc, | 206 | void Bu::ParamProc::addParam( char cChar, Proc proc, |
207 | const char *lpDesc, const char *lpExtra, | 207 | const char *lpDesc, const char *lpExtra, |
208 | const char *lpValue ) | 208 | const char *lpValue ) |
209 | { | 209 | { |
210 | addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); | 210 | addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); |
211 | } | 211 | } |
212 | 212 | ||
213 | void ParamProc::addParam( char cChar, ParamPtr val, | 213 | void Bu::ParamProc::addParam( char cChar, ParamPtr val, |
214 | const char *lpDesc, const char *lpExtra, | 214 | const char *lpDesc, const char *lpExtra, |
215 | const char *lpValue ) | 215 | const char *lpValue ) |
216 | { | 216 | { |
217 | addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); | 217 | addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); |
218 | } | 218 | } |
219 | 219 | ||
220 | void ParamProc::process( int argc, char *argv[] ) | 220 | void Bu::ParamProc::process( int argc, char *argv[] ) |
221 | { | 221 | { |
222 | for( int arg = 1; arg < argc; arg++ ) | 222 | for( int arg = 1; arg < argc; arg++ ) |
223 | { | 223 | { |
@@ -229,23 +229,23 @@ void ParamProc::process( int argc, char *argv[] ) | |||
229 | ArgSpec *s = checkWord( argv[arg]+2 ); | 229 | ArgSpec *s = checkWord( argv[arg]+2 ); |
230 | if( s ) | 230 | if( s ) |
231 | { | 231 | { |
232 | if( argv[arg][s->sWord.getLength()+2] == '=' ) | 232 | if( argv[arg][s->sWord.getSize()+2] == '=' ) |
233 | { | 233 | { |
234 | if( s->val.isSet() ) | 234 | if( s->val.isSet() ) |
235 | { | 235 | { |
236 | if( s->sValue.getString() == NULL ) | 236 | if( s->sValue.getStr() == NULL ) |
237 | { | 237 | { |
238 | s->val = argv[arg]+s->sWord.getLength()+3; | 238 | s->val = argv[arg]+s->sWord.getSize()+3; |
239 | } | 239 | } |
240 | else | 240 | else |
241 | { | 241 | { |
242 | s->val = s->sValue.getString(); | 242 | s->val = s->sValue.getStr(); |
243 | } | 243 | } |
244 | } | 244 | } |
245 | if( s->proc ) | 245 | if( s->proc ) |
246 | { | 246 | { |
247 | char **tmp = new char*[argc-arg]; | 247 | char **tmp = new char*[argc-arg]; |
248 | tmp[0] = argv[arg]+s->sWord.getLength()+3; | 248 | tmp[0] = argv[arg]+s->sWord.getSize()+3; |
249 | for( int k = 1; k < argc-arg; k++ ) | 249 | for( int k = 1; k < argc-arg; k++ ) |
250 | tmp[k] = argv[arg+k]; | 250 | tmp[k] = argv[arg+k]; |
251 | int ret = (this->*s->proc)( argc-arg, tmp ); | 251 | int ret = (this->*s->proc)( argc-arg, tmp ); |
@@ -261,7 +261,7 @@ void ParamProc::process( int argc, char *argv[] ) | |||
261 | int add = 0; | 261 | int add = 0; |
262 | if( s->val.isSet() ) | 262 | if( s->val.isSet() ) |
263 | { | 263 | { |
264 | if( s->sValue.getString() == NULL ) | 264 | if( s->sValue.getStr() == NULL ) |
265 | { | 265 | { |
266 | if( arg+1 >= argc ) | 266 | if( arg+1 >= argc ) |
267 | { | 267 | { |
@@ -272,7 +272,7 @@ void ParamProc::process( int argc, char *argv[] ) | |||
272 | } | 272 | } |
273 | else | 273 | else |
274 | { | 274 | { |
275 | s->val = s->sValue.getString(); | 275 | s->val = s->sValue.getStr(); |
276 | } | 276 | } |
277 | } | 277 | } |
278 | if( s->proc ) | 278 | if( s->proc ) |
@@ -307,14 +307,14 @@ void ParamProc::process( int argc, char *argv[] ) | |||
307 | bool bUsed = false; | 307 | bool bUsed = false; |
308 | if( s->val.isSet() ) | 308 | if( s->val.isSet() ) |
309 | { | 309 | { |
310 | if( s->sValue.getString() == NULL ) | 310 | if( s->sValue.getStr() == NULL ) |
311 | { | 311 | { |
312 | s->val = argv[arg]+chr+1; | 312 | s->val = argv[arg]+chr+1; |
313 | bUsed = true; | 313 | bUsed = true; |
314 | } | 314 | } |
315 | else | 315 | else |
316 | { | 316 | { |
317 | s->val = s->sValue.getString(); | 317 | s->val = s->sValue.getStr(); |
318 | } | 318 | } |
319 | } | 319 | } |
320 | if( s->proc ) | 320 | if( s->proc ) |
@@ -342,14 +342,14 @@ void ParamProc::process( int argc, char *argv[] ) | |||
342 | bool bUsed = false; | 342 | bool bUsed = false; |
343 | if( s->val.isSet() ) | 343 | if( s->val.isSet() ) |
344 | { | 344 | { |
345 | if( s->sValue.getString() == NULL ) | 345 | if( s->sValue.getStr() == NULL ) |
346 | { | 346 | { |
347 | s->val = argv[arg+1]; | 347 | s->val = argv[arg+1]; |
348 | bUsed = true; | 348 | bUsed = true; |
349 | } | 349 | } |
350 | else | 350 | else |
351 | { | 351 | { |
352 | s->val = s->sValue.getString(); | 352 | s->val = s->sValue.getStr(); |
353 | } | 353 | } |
354 | } | 354 | } |
355 | if( s->proc ) | 355 | if( s->proc ) |
@@ -384,22 +384,22 @@ void ParamProc::process( int argc, char *argv[] ) | |||
384 | } | 384 | } |
385 | } | 385 | } |
386 | 386 | ||
387 | ParamProc::ArgSpec *ParamProc::checkWord( const char *arg ) | 387 | Bu::ParamProc::ArgSpec *Bu::ParamProc::checkWord( const char *arg ) |
388 | { | 388 | { |
389 | //printf("Checking \"%s\"...\n", arg ); | 389 | //printf("Checking \"%s\"...\n", arg ); |
390 | std::list<ArgSpec *>::const_iterator i; | 390 | std::list<ArgSpec *>::const_iterator i; |
391 | for( i = lArg.begin(); i != lArg.end(); i++ ) | 391 | for( i = lArg.begin(); i != lArg.end(); i++ ) |
392 | { | 392 | { |
393 | if( (*i)->sWord.getString() == NULL ) | 393 | if( (*i)->sWord.getStr() == NULL ) |
394 | continue; | 394 | continue; |
395 | 395 | ||
396 | if( !strcmp( (*i)->sWord, arg ) ) | 396 | if( !strcmp( (*i)->sWord.getStr(), arg ) ) |
397 | return *i; | 397 | return *i; |
398 | 398 | ||
399 | if( (*i)->val.isSet() ) | 399 | if( (*i)->val.isSet() ) |
400 | { | 400 | { |
401 | if( !strncmp( (*i)->sWord, arg, (*i)->sWord.getLength() ) && | 401 | if( !strncmp( (*i)->sWord.getStr(), arg, (*i)->sWord.getSize() ) && |
402 | arg[(*i)->sWord.getLength()] == '=' ) | 402 | arg[(*i)->sWord.getSize()] == '=' ) |
403 | { | 403 | { |
404 | return *i; | 404 | return *i; |
405 | } | 405 | } |
@@ -409,7 +409,7 @@ ParamProc::ArgSpec *ParamProc::checkWord( const char *arg ) | |||
409 | return NULL; | 409 | return NULL; |
410 | } | 410 | } |
411 | 411 | ||
412 | ParamProc::ArgSpec *ParamProc::checkLetr( const char arg ) | 412 | Bu::ParamProc::ArgSpec *Bu::ParamProc::checkLetr( const char arg ) |
413 | { | 413 | { |
414 | //printf("Checking \'%c\'...\n", arg ); | 414 | //printf("Checking \'%c\'...\n", arg ); |
415 | std::list<ArgSpec *>::const_iterator i; | 415 | std::list<ArgSpec *>::const_iterator i; |
@@ -427,27 +427,27 @@ ParamProc::ArgSpec *ParamProc::checkLetr( const char arg ) | |||
427 | return NULL; | 427 | return NULL; |
428 | } | 428 | } |
429 | 429 | ||
430 | int ParamProc::cmdParam( int argc, char *argv[] ) | 430 | int Bu::ParamProc::cmdParam( int argc, char *argv[] ) |
431 | { | 431 | { |
432 | printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); | 432 | printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); |
433 | return 0; | 433 | return 0; |
434 | } | 434 | } |
435 | 435 | ||
436 | int ParamProc::unknownParam( int argc, char *argv[] ) | 436 | int Bu::ParamProc::unknownParam( int argc, char *argv[] ) |
437 | { | 437 | { |
438 | printf("Unknown parameter \"%s\" found!\n", argv[0] ); | 438 | printf("Unknown parameter \"%s\" found!\n", argv[0] ); |
439 | return 0; | 439 | return 0; |
440 | } | 440 | } |
441 | 441 | ||
442 | int ParamProc::help( int argc, char *argv[] ) | 442 | int Bu::ParamProc::help( int argc, char *argv[] ) |
443 | { | 443 | { |
444 | std::list<Banner *>::const_iterator b = lBan.begin(); | 444 | std::list<Banner *>::const_iterator b = lBan.begin(); |
445 | std::list<ArgSpec *>::const_iterator i; | 445 | std::list<ArgSpec *>::const_iterator i; |
446 | int len=0; | 446 | int len=0; |
447 | for( i = lArg.begin(); i != lArg.end(); i++ ) | 447 | for( i = lArg.begin(); i != lArg.end(); i++ ) |
448 | { | 448 | { |
449 | if( len < (*i)->sWord.getLength() + (*i)->sExtra.getLength() ) | 449 | if( len < (*i)->sWord.getSize() + (*i)->sExtra.getSize() ) |
450 | len = (*i)->sWord.getLength() + (*i)->sExtra.getLength(); | 450 | len = (*i)->sWord.getSize() + (*i)->sExtra.getSize(); |
451 | } | 451 | } |
452 | char fmt[10]; | 452 | char fmt[10]; |
453 | sprintf( fmt, "%%-%ds ", len ); | 453 | sprintf( fmt, "%%-%ds ", len ); |
@@ -458,14 +458,14 @@ int ParamProc::help( int argc, char *argv[] ) | |||
458 | { | 458 | { |
459 | if( (*b)->pBefore == (*i) ) | 459 | if( (*b)->pBefore == (*i) ) |
460 | { | 460 | { |
461 | printf( (*b)->sBanner.getString() ); | 461 | printf( (*b)->sBanner.getStr() ); |
462 | b++; | 462 | b++; |
463 | } | 463 | } |
464 | } | 464 | } |
465 | printf(" "); | 465 | printf(" "); |
466 | if( (*i)->cChar ) | 466 | if( (*i)->cChar ) |
467 | { | 467 | { |
468 | if( (*i)->sWord.getString() ) | 468 | if( (*i)->sWord.getStr() ) |
469 | { | 469 | { |
470 | printf("-%c, ", (*i)->cChar ); | 470 | printf("-%c, ", (*i)->cChar ); |
471 | } | 471 | } |
@@ -478,12 +478,12 @@ int ParamProc::help( int argc, char *argv[] ) | |||
478 | { | 478 | { |
479 | printf(" "); | 479 | printf(" "); |
480 | } | 480 | } |
481 | if( (*i)->sWord.getString() ) | 481 | if( (*i)->sWord.getStr() ) |
482 | { | 482 | { |
483 | printf("--"); | 483 | printf("--"); |
484 | std::string sTmp = (*i)->sWord.getString(); | 484 | std::string sTmp = (*i)->sWord.getStr(); |
485 | if( (*i)->sExtra.getString() ) | 485 | if( (*i)->sExtra.getStr() ) |
486 | sTmp += (*i)->sExtra.getString(); | 486 | sTmp += (*i)->sExtra.getStr(); |
487 | printf( fmt, sTmp.c_str() ); | 487 | printf( fmt, sTmp.c_str() ); |
488 | } | 488 | } |
489 | else | 489 | else |
@@ -491,20 +491,20 @@ int ParamProc::help( int argc, char *argv[] ) | |||
491 | printf(" "); | 491 | printf(" "); |
492 | printf(fmt, "" ); | 492 | printf(fmt, "" ); |
493 | } | 493 | } |
494 | printf("%s\n", (*i)->sDesc.getString() ); | 494 | printf("%s\n", (*i)->sDesc.getStr() ); |
495 | } | 495 | } |
496 | if( b != lBan.end() ) | 496 | if( b != lBan.end() ) |
497 | { | 497 | { |
498 | if( (*b)->pBefore == NULL ) | 498 | if( (*b)->pBefore == NULL ) |
499 | { | 499 | { |
500 | printf( (*b)->sBanner.getString() ); | 500 | printf( (*b)->sBanner.getStr() ); |
501 | } | 501 | } |
502 | } | 502 | } |
503 | 503 | ||
504 | exit( 0 ); | 504 | exit( 0 ); |
505 | } | 505 | } |
506 | 506 | ||
507 | void ParamProc::addHelpBanner( const char *sHelpBanner ) | 507 | void Bu::ParamProc::addHelpBanner( const char *sHelpBanner ) |
508 | { | 508 | { |
509 | Banner *pBan = new Banner; | 509 | Banner *pBan = new Banner; |
510 | pBan->sBanner = sHelpBanner; | 510 | pBan->sBanner = sHelpBanner; |
diff --git a/src/paramproc.h b/src/paramproc.h index d857193..2bca588 100644 --- a/src/paramproc.h +++ b/src/paramproc.h | |||
@@ -1,153 +1,156 @@ | |||
1 | #ifndef PARAM_PROC_H | 1 | #ifndef BU_PARAM_PROC_H |
2 | #define PARAM_PROC_H | 2 | #define BU_PARAM_PROC_H |
3 | 3 | ||
4 | #include <stdint.h> | 4 | #include <stdint.h> |
5 | #include <string> | 5 | #include <string> |
6 | #include <list> | 6 | #include <list> |
7 | #include "staticstring.h" | 7 | #include "bu/fstring.h" |
8 | 8 | ||
9 | class ParamProc | 9 | namespace Bu |
10 | { | 10 | { |
11 | public: | 11 | class ParamProc |
12 | class ParamPtr | ||
13 | { | 12 | { |
14 | public: | 13 | public: |
15 | ParamPtr(); | 14 | class ParamPtr |
16 | ParamPtr( std::string *str ); | ||
17 | ParamPtr( uint64_t *uint64 ); | ||
18 | ParamPtr( uint32_t *uint32 ); | ||
19 | ParamPtr( uint16_t *uint16 ); | ||
20 | ParamPtr( uint8_t *uint8 ); | ||
21 | ParamPtr( int64_t *int64 ); | ||
22 | ParamPtr( int32_t *int32 ); | ||
23 | ParamPtr( int16_t *int16 ); | ||
24 | ParamPtr( int8_t *int8 ); | ||
25 | ParamPtr( float *float32 ); | ||
26 | ParamPtr( double *float64 ); | ||
27 | ParamPtr( long double *float96 ); | ||
28 | ParamPtr( bool *bln ); | ||
29 | |||
30 | enum | ||
31 | { | 15 | { |
32 | vtunset, | 16 | public: |
33 | vtstr, | 17 | ParamPtr(); |
34 | vtuint64, | 18 | ParamPtr( std::string *str ); |
35 | vtuint32, | 19 | ParamPtr( uint64_t *uint64 ); |
36 | vtuint16, | 20 | ParamPtr( uint32_t *uint32 ); |
37 | vtuint8, | 21 | ParamPtr( uint16_t *uint16 ); |
38 | vtint64, | 22 | ParamPtr( uint8_t *uint8 ); |
39 | vtint32, | 23 | ParamPtr( int64_t *int64 ); |
40 | vtint16, | 24 | ParamPtr( int32_t *int32 ); |
41 | vtint8, | 25 | ParamPtr( int16_t *int16 ); |
42 | vtfloat32, | 26 | ParamPtr( int8_t *int8 ); |
43 | vtfloat64, | 27 | ParamPtr( float *float32 ); |
44 | vtfloat96, | 28 | ParamPtr( double *float64 ); |
45 | vtbln, | 29 | ParamPtr( long double *float96 ); |
46 | }; | 30 | ParamPtr( bool *bln ); |
47 | ParamPtr &operator=( ParamPtr &ptr ); | ||
48 | ParamPtr &operator=( const char *str ); | ||
49 | 31 | ||
50 | bool isSet(); | 32 | enum |
33 | { | ||
34 | vtunset, | ||
35 | vtstr, | ||
36 | vtuint64, | ||
37 | vtuint32, | ||
38 | vtuint16, | ||
39 | vtuint8, | ||
40 | vtint64, | ||
41 | vtint32, | ||
42 | vtint16, | ||
43 | vtint8, | ||
44 | vtfloat32, | ||
45 | vtfloat64, | ||
46 | vtfloat96, | ||
47 | vtbln, | ||
48 | }; | ||
49 | ParamPtr &operator=( ParamPtr &ptr ); | ||
50 | ParamPtr &operator=( const char *str ); | ||
51 | 51 | ||
52 | private: | 52 | bool isSet(); |
53 | int type; | 53 | |
54 | union | 54 | private: |
55 | { | 55 | int type; |
56 | std::string *str; | 56 | union |
57 | uint64_t *uint64; | 57 | { |
58 | uint32_t *uint32; | 58 | std::string *str; |
59 | uint16_t *uint16; | 59 | uint64_t *uint64; |
60 | uint8_t *uint8; | 60 | uint32_t *uint32; |
61 | int64_t *int64; | 61 | uint16_t *uint16; |
62 | int32_t *int32; | 62 | uint8_t *uint8; |
63 | int16_t *int16; | 63 | int64_t *int64; |
64 | int8_t *int8; | 64 | int32_t *int32; |
65 | float *float32; | 65 | int16_t *int16; |
66 | double *float64; | 66 | int8_t *int8; |
67 | long double *float96; | 67 | float *float32; |
68 | bool *bln; | 68 | double *float64; |
69 | } val; | 69 | long double *float96; |
70 | }; | 70 | bool *bln; |
71 | } val; | ||
72 | }; | ||
71 | 73 | ||
72 | typedef int (ParamProc::*Proc)( int, char *[] ); | 74 | typedef int (ParamProc::*Proc)( int, char *[] ); |
73 | 75 | ||
74 | typedef struct ArgSpec | 76 | typedef struct ArgSpec |
75 | { | 77 | { |
76 | uint8_t nFlags; | 78 | uint8_t nFlags; |
77 | StaticString sWord; | 79 | Bu::FString sWord; |
78 | char cChar; | 80 | char cChar; |
79 | Proc proc; | 81 | Proc proc; |
80 | ParamProc::ParamPtr val; | 82 | ParamProc::ParamPtr val; |
81 | StaticString sExtra; | 83 | Bu::FString sExtra; |
82 | StaticString sDesc; | 84 | Bu::FString sDesc; |
83 | StaticString sValue; | 85 | Bu::FString sValue; |
84 | } ArgSpec; | 86 | } ArgSpec; |
85 | 87 | ||
86 | public: | 88 | public: |
87 | ParamProc(); | 89 | ParamProc(); |
88 | virtual ~ParamProc(); | 90 | virtual ~ParamProc(); |
89 | 91 | ||
90 | void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, | 92 | void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, |
91 | const char *lpDesc=NULL, const char *lpExtra=NULL, | 93 | const char *lpDesc=NULL, const char *lpExtra=NULL, |
92 | const char *lpValue=NULL | 94 | const char *lpValue=NULL |
93 | ); | 95 | ); |
94 | void addParam( const char *lpWord, char cChar, Proc proc, | 96 | void addParam( const char *lpWord, char cChar, Proc proc, |
95 | const char *lpDesc=NULL, const char *lpExtra=NULL, | 97 | const char *lpDesc=NULL, const char *lpExtra=NULL, |
96 | const char *lpValue=NULL | 98 | const char *lpValue=NULL |
97 | ); | 99 | ); |
98 | void addParam( const char *lpWord, char cChar, ParamPtr val, | 100 | void addParam( const char *lpWord, char cChar, ParamPtr val, |
99 | const char *lpDesc=NULL, const char *lpExtra=NULL, | 101 | const char *lpDesc=NULL, const char *lpExtra=NULL, |
100 | const char *lpValue=NULL | 102 | const char *lpValue=NULL |
101 | ); | 103 | ); |
102 | 104 | ||
103 | void addParam( const char *lpWord, Proc proc, ParamPtr val, | 105 | void addParam( const char *lpWord, Proc proc, ParamPtr val, |
104 | const char *lpDesc=NULL, const char *lpExtra=NULL, | 106 | const char *lpDesc=NULL, const char *lpExtra=NULL, |
105 | const char *lpValue=NULL | 107 | const char *lpValue=NULL |
106 | ); | 108 | ); |
107 | void addParam( const char *lpWord, Proc proc, | 109 | void addParam( const char *lpWord, Proc proc, |
108 | const char *lpDesc=NULL, const char *lpExtra=NULL, | 110 | const char *lpDesc=NULL, const char *lpExtra=NULL, |
109 | const char *lpValue=NULL | 111 | const char *lpValue=NULL |
110 | ); | 112 | ); |
111 | void addParam( const char *lpWord, ParamPtr val, | 113 | void addParam( const char *lpWord, ParamPtr val, |
112 | const char *lpDesc=NULL, const char *lpExtra=NULL, | 114 | const char *lpDesc=NULL, const char *lpExtra=NULL, |
113 | const char *lpValue=NULL | 115 | const char *lpValue=NULL |
114 | ); | 116 | ); |
115 | 117 | ||
116 | void addParam( char cChar, Proc proc, ParamPtr val, | 118 | void addParam( char cChar, Proc proc, ParamPtr val, |
117 | const char *lpDesc=NULL, const char *lpExtra=NULL, | 119 | const char *lpDesc=NULL, const char *lpExtra=NULL, |
118 | const char *lpValue=NULL | 120 | const char *lpValue=NULL |
119 | ); | 121 | ); |
120 | void addParam( char cChar, Proc proc, | 122 | void addParam( char cChar, Proc proc, |
121 | const char *lpDesc=NULL, const char *lpExtra=NULL, | 123 | const char *lpDesc=NULL, const char *lpExtra=NULL, |
122 | const char *lpValue=NULL | 124 | const char *lpValue=NULL |
123 | ); | 125 | ); |
124 | void addParam( char cChar, ParamPtr val, | 126 | void addParam( char cChar, ParamPtr val, |
125 | const char *lpDesc=NULL, const char *lpExtra=NULL, | 127 | const char *lpDesc=NULL, const char *lpExtra=NULL, |
126 | const char *lpValue=NULL | 128 | const char *lpValue=NULL |
127 | ); | 129 | ); |
128 | 130 | ||
129 | void process( int argc, char *argv[] ); | 131 | void process( int argc, char *argv[] ); |
130 | void addHelpBanner( const char *sHelpBanner ); | 132 | void addHelpBanner( const char *sHelpBanner ); |
131 | 133 | ||
132 | private: | 134 | private: |
133 | ArgSpec *checkWord( const char *arg ); | 135 | ArgSpec *checkWord( const char *arg ); |
134 | ArgSpec *checkLetr( const char arg ); | 136 | ArgSpec *checkLetr( const char arg ); |
135 | 137 | ||
136 | public: | 138 | public: |
137 | virtual int cmdParam( int argc, char *argv[] ); | 139 | virtual int cmdParam( int argc, char *argv[] ); |
138 | virtual int unknownParam( int argc, char *argv[] ); | 140 | virtual int unknownParam( int argc, char *argv[] ); |
139 | virtual int help( int argc, char *argv[] ); | 141 | virtual int help( int argc, char *argv[] ); |
140 | 142 | ||
141 | private: | 143 | private: |
142 | typedef struct Banner | 144 | typedef struct Banner |
143 | { | 145 | { |
144 | StaticString sBanner; | 146 | Bu::FString sBanner; |
145 | ArgSpec *pBefore; | 147 | ArgSpec *pBefore; |
146 | } Banner; | 148 | } Banner; |
147 | std::list<Banner *> lBan; | 149 | std::list<Banner *> lBan; |
148 | std::list<ArgSpec *> lArg; | 150 | std::list<ArgSpec *> lArg; |
149 | }; | 151 | }; |
152 | } | ||
150 | 153 | ||
151 | #define mkproc( cls ) static_cast<int (ParamProc::*)( int, char *[])>(&cls) | 154 | #define mkproc( cls ) static_cast<int (Bu::ParamProc::*)( int, char *[])>(&cls) |
152 | 155 | ||
153 | #endif | 156 | #endif |
diff --git a/src/plugger.h b/src/plugger.h index d92f194..2124b7a 100644 --- a/src/plugger.h +++ b/src/plugger.h | |||
@@ -1,198 +1,198 @@ | |||
1 | #ifndef PLUGGER_H | 1 | #ifndef BU_PLUGGER_H |
2 | #define PLUGGER_H | 2 | #define BU_PLUGGER_H |
3 | 3 | ||
4 | 4 | ||
5 | #include "hashtable.h" | 5 | #include "bu/hash.h" |
6 | #include "list" | 6 | #include "bu/list.h" |
7 | #include "hashfunctionstring.h" | 7 | #include <dlfcn.h> |
8 | #include "hashfunctionint.h" | 8 | #include "bu/exceptions.h" |
9 | #include "dlfcn.h" | 9 | #include "bu/fstring.h" |
10 | #include "exceptions.h" | ||
11 | 10 | ||
12 | typedef struct PluginInfo | 11 | namespace Bu |
13 | { | 12 | { |
14 | const char *sID; | 13 | typedef struct PluginInfo |
15 | const char *sAuthor; | 14 | { |
16 | unsigned short nVersion; | 15 | const char *sID; |
17 | unsigned short nRevision; | 16 | const char *sAuthor; |
18 | void *(*createPlugin)(); | 17 | unsigned short nVersion; |
19 | void (*destroyPlugin)( void * ); | 18 | unsigned short nRevision; |
20 | } PluginInfo; | 19 | void *(*createPlugin)(); |
21 | 20 | void (*destroyPlugin)( void * ); | |
22 | typedef struct PluginReg | 21 | } PluginInfo; |
23 | { | 22 | |
24 | bool bBuiltin; | 23 | typedef struct PluginReg |
25 | void *dlHandle; | 24 | { |
26 | PluginInfo *pInfo; | 25 | bool bBuiltin; |
27 | } PluginReg; | 26 | void *dlHandle; |
27 | PluginInfo *pInfo; | ||
28 | } PluginReg; | ||
28 | 29 | ||
29 | #define PluginInterface( classname, baseclass, name, ver, rev ) \ | 30 | #define PluginInterface( classname, baseclass, name, ver, rev ) \ |
30 | extern "C" { \ | 31 | extern "C" { \ |
31 | baseclass *create ##classname() \ | 32 | baseclass *create ##classname() \ |
32 | { \ | 33 | { \ |
33 | return new classname(); \ | 34 | return new classname(); \ |
34 | } \ | 35 | } \ |
35 | void destroy ##classname( baseclass *pCls ) \ | 36 | void destroy ##classname( baseclass *pCls ) \ |
36 | { \ | 37 | { \ |
37 | delete pCls; \ | 38 | delete pCls; \ |
38 | } \ | 39 | } \ |
39 | PluginInfo classname = { \ | 40 | Bu::PluginInfo classname = { \ |
40 | #classname, name, ver, rev, \ | 41 | #classname, name, ver, rev, \ |
41 | create ##classname, destroy ##classname }; \ | 42 | create ##classname, destroy ##classname }; \ |
42 | } | 43 | } |
43 | 44 | ||
44 | #define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \ | 45 | #define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \ |
45 | extern "C" { \ | 46 | extern "C" { \ |
46 | baseclass *create ##classname() \ | 47 | baseclass *create ##classname() \ |
47 | { \ | 48 | { \ |
48 | return new classname(); \ | 49 | return new classname(); \ |
49 | } \ | 50 | } \ |
50 | void destroy ##classname( baseclass *pCls ) \ | 51 | void destroy ##classname( baseclass *pCls ) \ |
51 | { \ | 52 | { \ |
52 | delete pCls; \ | 53 | delete pCls; \ |
53 | } \ | 54 | } \ |
54 | PluginInfo pluginname = { \ | 55 | Bu::PluginInfo pluginname = { \ |
55 | #pluginname, name, ver, rev, \ | 56 | #pluginname, name, ver, rev, \ |
56 | (void *(*)())(create ##classname), \ | 57 | (void *(*)())(create ##classname), \ |
57 | (void (*)( void * ))(destroy ##classname) }; \ | 58 | (void (*)( void * ))(destroy ##classname) }; \ |
58 | } | 59 | } |
59 | 60 | ||
60 | #define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \ | 61 | #define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \ |
61 | extern "C" { \ | 62 | extern "C" { \ |
62 | baseclass *create ##classname() \ | 63 | baseclass *create ##classname() \ |
63 | { \ | 64 | { \ |
64 | return new classname(); \ | 65 | return new classname(); \ |
65 | } \ | 66 | } \ |
66 | void destroy ##classname( baseclass *pCls ) \ | 67 | void destroy ##classname( baseclass *pCls ) \ |
67 | { \ | 68 | { \ |
68 | delete pCls; \ | 69 | delete pCls; \ |
69 | } \ | 70 | } \ |
70 | PluginInfo structname = { \ | 71 | Bu::PluginInfo structname = { \ |
71 | #pluginname, name, ver, rev, \ | 72 | #pluginname, name, ver, rev, \ |
72 | (void *(*)())(create ##classname), \ | 73 | (void *(*)())(create ##classname), \ |
73 | (void (*)( void * ))(destroy ##classname) }; \ | 74 | (void (*)( void * ))(destroy ##classname) }; \ |
74 | } | ||
75 | |||
76 | template<class T> | ||
77 | class Plugger | ||
78 | { | ||
79 | public: | ||
80 | |||
81 | public: | ||
82 | Plugger() : | ||
83 | hPlugin( new HashFunctionString(), 11 ), | ||
84 | hObj( new HashFunctionInt(), 11 ) | ||
85 | { | ||
86 | } | 75 | } |
87 | 76 | ||
88 | virtual ~Plugger() | 77 | template<class T> |
78 | class Plugger | ||
89 | { | 79 | { |
90 | void *pos = hObj.getFirstItemPos(); | 80 | public: |
91 | while( (pos = hObj.getNextItemPos( pos )) ) | 81 | typedef Bu::Hash<Bu::FString, PluginReg *> PluginHash; |
82 | typedef Bu::Hash<int, void *> InstHash; | ||
83 | |||
84 | public: | ||
85 | Plugger() | ||
92 | { | 86 | { |
93 | T *pPlug = (T *)hObj.getItemID( pos ); | ||
94 | PluginReg *pReg = (PluginReg *)hObj.getItemData( pos ); | ||
95 | pReg->pInfo->destroyPlugin( pPlug ); | ||
96 | } | 87 | } |
97 | 88 | ||
98 | std::list<PluginReg *>::iterator i; | 89 | virtual ~Plugger() |
99 | for( i = lPlugin.begin(); i != lPlugin.end(); i++ ) | ||
100 | { | 90 | { |
101 | if( (*i)->bBuiltin == false ) | 91 | for( InstHash::iterator i = hObj.begin(); i != hObj.end(); i++ ) |
102 | { | 92 | { |
103 | dlclose( (*i)->dlHandle ); | 93 | T *pPlug = (T *)i.getKey(); |
94 | PluginReg *pReg = (PluginReg *)*i; | ||
95 | pReg->pInfo->destroyPlugin( pPlug ); | ||
104 | } | 96 | } |
105 | delete (*i); | ||
106 | } | ||
107 | } | ||
108 | 97 | ||
109 | void registerBuiltinPlugin( PluginInfo *pInfo ) | 98 | for( PluginHash::iterator i = hPlugin.begin(); |
110 | { | 99 | i != hPlugin.end(); i++ ) |
111 | PluginReg *pReg = new PluginReg; | 100 | { |
112 | pReg->bBuiltin = true; | 101 | if( (*i)->bBuiltin == false ) |
113 | pReg->pInfo = pInfo; | 102 | { |
114 | lPlugin.insert( lPlugin.end(), pReg ); | 103 | dlclose( (*i)->dlHandle ); |
115 | hPlugin.insert( pInfo->sID, pReg ); | 104 | } |
116 | } | 105 | delete (*i); |
106 | } | ||
107 | } | ||
117 | 108 | ||
118 | void registerExternalPlugin( const char *sFName, const char *sPluginName ) | 109 | void registerBuiltinPlugin( PluginInfo *pInfo ) |
119 | { | ||
120 | PluginReg *pReg = (PluginReg *)hPlugin[sPluginName]; | ||
121 | if( pReg != NULL ) | ||
122 | { | 110 | { |
123 | hPlugin.del( sPluginName ); | 111 | PluginReg *pReg = new PluginReg; |
124 | dlclose( pReg->dlHandle ); | 112 | pReg->bBuiltin = true; |
125 | delete pReg; | 113 | pReg->pInfo = pInfo; |
126 | pReg = NULL; | 114 | hPlugin.insert( pInfo->sID, pReg ); |
127 | } | 115 | } |
128 | 116 | ||
129 | pReg = new PluginReg; | 117 | void registerExternalPlugin( const char *sFName, const char *sPluginName ) |
130 | |||
131 | pReg->bBuiltin = false; | ||
132 | pReg->dlHandle = dlopen( sFName, RTLD_NOW ); | ||
133 | if( pReg->dlHandle == NULL ) | ||
134 | { | 118 | { |
135 | throw PluginException( 1, "Error on %s: %s", sFName, dlerror() ); | 119 | PluginReg *pReg; |
120 | try { | ||
121 | pReg = (PluginReg *)hPlugin[sPluginName]; | ||
122 | hPlugin.erase( sPluginName ); | ||
123 | dlclose( pReg->dlHandle ); | ||
124 | delete pReg; | ||
125 | pReg = NULL; | ||
126 | } catch( Bu::HashException &e ) | ||
127 | { | ||
128 | } | ||
129 | |||
130 | pReg = new PluginReg; | ||
131 | |||
132 | pReg->bBuiltin = false; | ||
133 | pReg->dlHandle = dlopen( sFName, RTLD_NOW ); | ||
134 | if( pReg->dlHandle == NULL ) | ||
135 | { | ||
136 | throw PluginException( 1, "Error on %s: %s", sFName, dlerror() ); | ||
137 | } | ||
138 | pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, sPluginName ); | ||
139 | if( pReg->pInfo == NULL ) | ||
140 | { | ||
141 | throw PluginException( 2, "Error on %s: %s", sFName, dlerror() ); | ||
142 | } | ||
143 | hPlugin.insert( pReg->pInfo->sID, pReg ); | ||
136 | } | 144 | } |
137 | pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, sPluginName ); | 145 | |
138 | if( pReg->pInfo == NULL ) | 146 | T *instantiate( const char *lpName ) |
139 | { | 147 | { |
140 | throw PluginException( 2, "Error on %s: %s", sFName, dlerror() ); | 148 | PluginReg *pReg = (PluginReg *)hPlugin[lpName]; |
149 | if( pReg == NULL ) | ||
150 | return NULL; | ||
151 | |||
152 | T *p = (T *)pReg->pInfo->createPlugin(); | ||
153 | hObj.insert( (int )p, pReg ); | ||
154 | //printf("pReg: %08X, pPlug: %08X\n", pReg, p ); | ||
155 | |||
156 | return p; | ||
141 | } | 157 | } |
142 | hPlugin.insert( pReg->pInfo->sID, pReg ); | ||
143 | lPlugin.insert( lPlugin.end(), pReg ); | ||
144 | } | ||
145 | |||
146 | T *instantiate( const char *lpName ) | ||
147 | { | ||
148 | PluginReg *pReg = (PluginReg *)hPlugin[lpName]; | ||
149 | if( pReg == NULL ) | ||
150 | return NULL; | ||
151 | |||
152 | T *p = (T *)pReg->pInfo->createPlugin(); | ||
153 | hObj.insert( p, pReg ); | ||
154 | //printf("pReg: %08X, pPlug: %08X\n", pReg, p ); | ||
155 | |||
156 | return p; | ||
157 | } | ||
158 | 158 | ||
159 | bool hasPlugin( const char *lpName ) | 159 | bool hasPlugin( const char *lpName ) |
160 | { | 160 | { |
161 | if( hPlugin[lpName] == NULL ) | 161 | if( hPlugin[lpName] == NULL ) |
162 | return false; | 162 | return false; |
163 | return true; | 163 | return true; |
164 | } | 164 | } |
165 | 165 | ||
166 | void destroy( T *pPlug ) | 166 | void destroy( T *pPlug ) |
167 | { | 167 | { |
168 | PluginReg *pReg = (PluginReg *)hObj[pPlug]; | 168 | PluginReg *pReg = (PluginReg *)hObj.get((int)pPlug); |
169 | //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug ); | 169 | //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug ); |
170 | if( pReg == NULL ) | 170 | if( pReg == NULL ) |
171 | return; | 171 | return; |
172 | 172 | ||
173 | pReg->pInfo->destroyPlugin( pPlug ); | 173 | pReg->pInfo->destroyPlugin( pPlug ); |
174 | 174 | ||
175 | hObj.del( pPlug ); | 175 | hObj.erase( (int)pPlug ); |
176 | } | 176 | } |
177 | 177 | ||
178 | void unloadAll() | 178 | void unloadAll() |
179 | { | ||
180 | std::list<PluginReg *>::iterator i; | ||
181 | for( i = lPlugin.begin(); i != lPlugin.end(); i++ ) | ||
182 | { | 179 | { |
183 | if( (*i)->bBuiltin == false ) | 180 | for( PluginHash::iterator i = hPlugin.begin(); |
181 | i != hPlugin.end(); i++ ) | ||
184 | { | 182 | { |
185 | dlclose( (*i)->dlHandle ); | 183 | if( (*i)->bBuiltin == false ) |
184 | { | ||
185 | dlclose( (*i)->dlHandle ); | ||
186 | } | ||
187 | delete (*i); | ||
186 | } | 188 | } |
187 | delete (*i); | 189 | hPlugin.clear(); |
188 | } | 190 | } |
189 | hPlugin.clear(); | ||
190 | } | ||
191 | 191 | ||
192 | private: | 192 | private: |
193 | std::list<PluginReg *> lPlugin; | 193 | PluginHash hPlugin; |
194 | HashTable hPlugin; | 194 | InstHash hObj; |
195 | HashTable hObj; | 195 | }; |
196 | }; | 196 | } |
197 | 197 | ||
198 | #endif | 198 | #endif |
diff --git a/src/programchain.cpp b/src/programchain.cpp index 6120d58..0bb7a77 100644 --- a/src/programchain.cpp +++ b/src/programchain.cpp | |||
@@ -1,17 +1,18 @@ | |||
1 | #include <stdlib.h> | 1 | #include <stdlib.h> |
2 | #include "programchain.h" | 2 | #include "bu/programchain.h" |
3 | #include "bu/programlink.h" | ||
3 | 4 | ||
4 | ProgramChain::ProgramChain() : | 5 | using namespace Bu; |
5 | xLog( MultiLog::getInstance() ) | 6 | |
7 | Bu::ProgramChain::ProgramChain() | ||
6 | { | 8 | { |
7 | xLog.LineLog( MultiLog::LStatus, "Program Chain Initialized." ); | ||
8 | } | 9 | } |
9 | 10 | ||
10 | ProgramChain::~ProgramChain() | 11 | Bu::ProgramChain::~ProgramChain() |
11 | { | 12 | { |
12 | } | 13 | } |
13 | 14 | ||
14 | bool ProgramChain::addLink( ProgramLink *pLink ) | 15 | bool Bu::ProgramChain::addLink( ProgramLink *pLink ) |
15 | { | 16 | { |
16 | if( pLink->init() == false ) | 17 | if( pLink->init() == false ) |
17 | { | 18 | { |
@@ -26,26 +27,25 @@ bool ProgramChain::addLink( ProgramLink *pLink ) | |||
26 | return true; | 27 | return true; |
27 | } | 28 | } |
28 | 29 | ||
29 | ProgramLink *ProgramChain::getLink( const char *lpName ) | 30 | ProgramLink *Bu::ProgramChain::getLink( const char *lpName ) |
30 | { | 31 | { |
31 | char a; | 32 | char a; |
32 | a = lpName[0]; | 33 | a = lpName[0]; |
33 | return NULL; | 34 | return NULL; |
34 | } | 35 | } |
35 | 36 | ||
36 | ProgramLink *ProgramChain::getBaseLink() | 37 | ProgramLink *Bu::ProgramChain::getBaseLink() |
37 | { | 38 | { |
38 | return NULL; | 39 | return NULL; |
39 | } | 40 | } |
40 | 41 | ||
41 | bool ProgramChain::execChainOnce() | 42 | bool Bu::ProgramChain::execChainOnce() |
42 | { | 43 | { |
43 | int nLen = lLink.getSize(); | 44 | for( Bu::List<Bu::ProgramLink *>::iterator i = lLink.begin(); |
44 | for( int j = 0; j < nLen; j++ ) | 45 | i != lLink.end(); i++ ) |
45 | { | 46 | { |
46 | if( ((ProgramLink *)lLink[j])->timeSlice() == false ) | 47 | if( (*i)->timeSlice() == false ) |
47 | { | 48 | { |
48 | xLog.LineLog( MultiLog::LInfo, "Shutting down due to signal from link #%d", j ); | ||
49 | emergencyShutdown(); | 49 | emergencyShutdown(); |
50 | return false; | 50 | return false; |
51 | } | 51 | } |
@@ -54,7 +54,7 @@ bool ProgramChain::execChainOnce() | |||
54 | return true; | 54 | return true; |
55 | } | 55 | } |
56 | 56 | ||
57 | bool ProgramChain::enterChainLoop() | 57 | bool Bu::ProgramChain::enterChainLoop() |
58 | { | 58 | { |
59 | for(;;) | 59 | for(;;) |
60 | { | 60 | { |
@@ -67,23 +67,23 @@ bool ProgramChain::enterChainLoop() | |||
67 | return true; | 67 | return true; |
68 | } | 68 | } |
69 | 69 | ||
70 | void ProgramChain::emergencyShutdown() | 70 | void Bu::ProgramChain::emergencyShutdown() |
71 | { | 71 | { |
72 | int nLen = lLink.getSize(); | 72 | for( Bu::List<Bu::ProgramLink *>::iterator i = lLink.begin(); |
73 | for( int j = 0; j < nLen; j++ ) | 73 | i != lLink.end(); i++ ) |
74 | { | 74 | { |
75 | ((ProgramLink *)lLink[j])->deInit(); | 75 | (*i)->deInit(); |
76 | delete (ProgramLink *)lLink[j]; | 76 | delete *i; |
77 | } | 77 | } |
78 | lLink.empty(); | 78 | lLink.clear(); |
79 | } | 79 | } |
80 | 80 | ||
81 | LinkMessage *ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ) | 81 | LinkMessage *Bu::ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ) |
82 | { | 82 | { |
83 | int nLen = lLink.getSize(); | 83 | for( Bu::List<Bu::ProgramLink *>::iterator i = lLink.begin(); |
84 | for( int j = 0; j < nLen; j++ ) | 84 | i != lLink.end(); i++ ) |
85 | { | 85 | { |
86 | LinkMessage *pMsg = ((ProgramLink *)lLink[j])->processIRM( pMsgOut ); | 86 | LinkMessage *pMsg = (*i)->processIRM( pMsgOut ); |
87 | if( pMsg != NULL ) | 87 | if( pMsg != NULL ) |
88 | { | 88 | { |
89 | delete pMsgOut; | 89 | delete pMsgOut; |
@@ -94,3 +94,4 @@ LinkMessage *ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSen | |||
94 | delete pMsgOut; | 94 | delete pMsgOut; |
95 | return NULL; | 95 | return NULL; |
96 | } | 96 | } |
97 | |||
diff --git a/src/programchain.h b/src/programchain.h index 2bdfeee..336a9f1 100644 --- a/src/programchain.h +++ b/src/programchain.h | |||
@@ -1,95 +1,98 @@ | |||
1 | #ifndef PROGRAMCHAIN_H | 1 | #ifndef BU_PROGRAMCHAIN_H |
2 | #define PROGRAMCHAIN_H | 2 | #define BU_PROGRAMCHAIN_H |
3 | 3 | ||
4 | #include "linkedlist.h" | 4 | #include "bu/list.h" |
5 | #include "multilog.h" | 5 | #include "bu/linkmessage.h" |
6 | #include "programlink.h" | ||
7 | 6 | ||
8 | /** | 7 | namespace Bu |
9 | * The Program Chain links together program "chunks" to more easily facilitate | ||
10 | * a generalized program loop with modular extensions. | ||
11 | *@author Mike Buland | ||
12 | */ | ||
13 | class ProgramChain | ||
14 | { | 8 | { |
15 | public: | 9 | class ProgramLink; |
16 | /** | 10 | /** |
17 | * Construct an empty chain. | 11 | * The Program Chain links together program "chunks" to more easily facilitate |
12 | * a generalized program loop with modular extensions. | ||
13 | *@author Mike Buland | ||
18 | */ | 14 | */ |
19 | ProgramChain(); | 15 | class ProgramChain |
16 | { | ||
17 | public: | ||
18 | /** | ||
19 | * Construct an empty chain. | ||
20 | */ | ||
21 | ProgramChain(); | ||
20 | 22 | ||
21 | /** | 23 | /** |
22 | * Destroy your chain. | 24 | * Destroy your chain. |
23 | */ | 25 | */ |
24 | virtual ~ProgramChain(); | 26 | virtual ~ProgramChain(); |
25 | 27 | ||
26 | /** | 28 | /** |
27 | * Adds a link to the end of the chain. | 29 | * Adds a link to the end of the chain. |
28 | *@param pLink A pointer to the link to add to the chain. | 30 | *@param pLink A pointer to the link to add to the chain. |
29 | *@returns True if adding the link was successful, otherwise false | 31 | *@returns True if adding the link was successful, otherwise false |
30 | *@author Mike Buland | 32 | *@author Mike Buland |
31 | */ | 33 | */ |
32 | bool addLink( ProgramLink *pLink ); | 34 | bool addLink( Bu::ProgramLink *pLink ); |
33 | 35 | ||
34 | /** | 36 | /** |
35 | * Gets a link by name. | 37 | * Gets a link by name. |
36 | *@param lpName The name of the link you're looking for. Every link has a | 38 | *@param lpName The name of the link you're looking for. Every link has a |
37 | * name, apparently. | 39 | * name, apparently. |
38 | *@returns A pointer to the specified ProgramLink, or NULL if none were | 40 | *@returns A pointer to the specified ProgramLink, or NULL if none were |
39 | * found matching your criteria. | 41 | * found matching your criteria. |
40 | *@author Mike Buland | 42 | *@author Mike Buland |
41 | */ | 43 | */ |
42 | class ProgramLink *getLink( const char *lpName ); | 44 | class ProgramLink *getLink( const char *lpName ); |
43 | 45 | ||
44 | /** | 46 | /** |
45 | * Gets the very first link in the chain. | 47 | * Gets the very first link in the chain. |
46 | *@returns A pointer to the first link in the chain. | 48 | *@returns A pointer to the first link in the chain. |
47 | *@author Mike Buland | 49 | *@author Mike Buland |
48 | */ | 50 | */ |
49 | class ProgramLink *getBaseLink(); | 51 | class ProgramLink *getBaseLink(); |
50 | 52 | ||
51 | /** | 53 | /** |
52 | * Runs through the chain once. Useful if you want to have more control | 54 | * Runs through the chain once. Useful if you want to have more control |
53 | * over the operation of the chain. | 55 | * over the operation of the chain. |
54 | *@returns true if every link returned true. If at least one link returns | 56 | *@returns true if every link returned true. If at least one link returns |
55 | * false, then returns false. | 57 | * false, then returns false. |
56 | *@author Mike Buland | 58 | *@author Mike Buland |
57 | */ | 59 | */ |
58 | bool execChainOnce(); | 60 | bool execChainOnce(); |
59 | 61 | ||
60 | /** | 62 | /** |
61 | * Enters the master chain loop, looping over the entire chain and | 63 | * Enters the master chain loop, looping over the entire chain and |
62 | * executing every link's TimeSlice routine in order, over and over, until | 64 | * executing every link's TimeSlice routine in order, over and over, until |
63 | * a link returns a false value. | 65 | * a link returns a false value. |
64 | *@returns False, always. It returns true unless a link returned false, | 66 | *@returns False, always. It returns true unless a link returned false, |
65 | * but loops until a link does return false. | 67 | * but loops until a link does return false. |
66 | *@author Mike Buland | 68 | *@author Mike Buland |
67 | **/ | 69 | **/ |
68 | bool enterChainLoop(); | 70 | bool enterChainLoop(); |
69 | 71 | ||
70 | /** | 72 | /** |
71 | * Broadcasts an Immediate Response Message to all active links, save the | 73 | * Broadcasts an Immediate Response Message to all active links, save the |
72 | * sender. Whatever link first responds with a non-null response message | 74 | * sender. Whatever link first responds with a non-null response message |
73 | * will have it's messages sent back to the broadcasting link as the returns | 75 | * will have it's messages sent back to the broadcasting link as the returns |
74 | * of this function call. Therefore it is very important that all message | 76 | * of this function call. Therefore it is very important that all message |
75 | * processing code is handled in a fairly timely fasion. | 77 | * processing code is handled in a fairly timely fasion. |
76 | *@param pMsgOut The message to broadcast in hopes of a response. | 78 | *@param pMsgOut The message to broadcast in hopes of a response. |
77 | *@param pSender The message that sent out the message and doesn't want to | 79 | *@param pSender The message that sent out the message and doesn't want to |
78 | * receive it's own message. This should always just be "this". | 80 | * receive it's own message. This should always just be "this". |
79 | *@returns The message that was returned by the first link to return a | 81 | *@returns The message that was returned by the first link to return a |
80 | * non-null response. If all messages return null responses then this also | 82 | * non-null response. If all messages return null responses then this also |
81 | * returns null. Please note that whoever calls this will be responsible | 83 | * returns null. Please note that whoever calls this will be responsible |
82 | * for deleting the message returned by it, if non-null. | 84 | * for deleting the message returned by it, if non-null. |
83 | */ | 85 | */ |
84 | class LinkMessage *broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ); | 86 | class LinkMessage *broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ); |
87 | |||
88 | private: | ||
89 | /** | ||
90 | * Shuts down all operation no matter what point in the operation we were. | ||
91 | */ | ||
92 | void emergencyShutdown(); | ||
93 | Bu::List<Bu::ProgramLink *> lLink; /**< The linked list that contains all of the links. */ | ||
94 | }; | ||
95 | } | ||
85 | 96 | ||
86 | private: | ||
87 | /** | ||
88 | * Shuts down all operation no matter what point in the operation we were. | ||
89 | */ | ||
90 | void emergencyShutdown(); | ||
91 | MultiLog &xLog; /**< A reference to the log. */ | ||
92 | LinkedList lLink; /**< The linked list that contains all of the links. */ | ||
93 | }; | ||
94 | 97 | ||
95 | #endif | 98 | #endif |
diff --git a/src/programlink.cpp b/src/programlink.cpp index 21c6fe4..e5c624c 100644 --- a/src/programlink.cpp +++ b/src/programlink.cpp | |||
@@ -1,20 +1,22 @@ | |||
1 | #include "programlink.h" | 1 | #include "bu/programlink.h" |
2 | #include "programchain.h" | 2 | #include "bu/programchain.h" |
3 | 3 | ||
4 | ProgramLink::ProgramLink() | 4 | using namespace Bu; |
5 | |||
6 | Bu::ProgramLink::ProgramLink() | ||
5 | { | 7 | { |
6 | } | 8 | } |
7 | 9 | ||
8 | ProgramLink::~ProgramLink() | 10 | Bu::ProgramLink::~ProgramLink() |
9 | { | 11 | { |
10 | } | 12 | } |
11 | 13 | ||
12 | LinkMessage *ProgramLink::sendIRM( LinkMessage *pMsgOut ) | 14 | LinkMessage *Bu::ProgramLink::sendIRM( LinkMessage *pMsgOut ) |
13 | { | 15 | { |
14 | return pChain->broadcastIRM( pMsgOut, this ); | 16 | return pChain->broadcastIRM( pMsgOut, this ); |
15 | } | 17 | } |
16 | 18 | ||
17 | void ProgramLink::setChain( ProgramChain *pNewChain ) | 19 | void Bu::ProgramLink::setChain( ProgramChain *pNewChain ) |
18 | { | 20 | { |
19 | pChain = pNewChain; | 21 | pChain = pNewChain; |
20 | } | 22 | } |
diff --git a/src/programlink.h b/src/programlink.h index f93edcc..07d7489 100644 --- a/src/programlink.h +++ b/src/programlink.h | |||
@@ -1,99 +1,100 @@ | |||
1 | #ifndef PROGRAMLINK_H | 1 | #ifndef BU_PROGRAMLINK_H |
2 | #define PROGRAMLINK_H | 2 | #define BU_PROGRAMLINK_H |
3 | 3 | ||
4 | class ProgramLink; | 4 | #include "bu/linkmessage.h" |
5 | #include "queue.h" | 5 | #include "bu/programchain.h" |
6 | #include "linkmessage.h" | ||
7 | #include "programchain.h" | ||
8 | 6 | ||
9 | /** | 7 | namespace Bu |
10 | * Program Link is the base class for any object that will be a piece of the | ||
11 | * main program chain loop. | ||
12 | *@author Mike Buland | ||
13 | */ | ||
14 | class ProgramLink | ||
15 | { | 8 | { |
16 | friend class ProgramChain; | ||
17 | public: | ||
18 | /** | 9 | /** |
19 | * Construct a program link. | 10 | * Program Link is the base class for any object that will be a piece of the |
11 | * main program chain loop. | ||
12 | *@author Mike Buland | ||
20 | */ | 13 | */ |
21 | ProgramLink(); | 14 | class ProgramLink |
15 | { | ||
16 | friend class Bu::ProgramChain; | ||
17 | public: | ||
18 | /** | ||
19 | * Construct a program link. | ||
20 | */ | ||
21 | ProgramLink(); | ||
22 | 22 | ||
23 | /** | 23 | /** |
24 | * Deconstruct. | 24 | * Deconstruct. |
25 | */ | 25 | */ |
26 | virtual ~ProgramLink(); | 26 | virtual ~ProgramLink(); |
27 | 27 | ||
28 | /** | 28 | /** |
29 | * Initialization code required for a link that wasn't performed in the | 29 | * Initialization code required for a link that wasn't performed in the |
30 | * constructor. | 30 | * constructor. |
31 | *@returns true if initialization was successful. A false value will halt | 31 | *@returns true if initialization was successful. A false value will halt |
32 | * the chain. | 32 | * the chain. |
33 | */ | 33 | */ |
34 | virtual bool init()=0; | 34 | virtual bool init()=0; |
35 | 35 | ||
36 | /** | 36 | /** |
37 | * DeInitialization code that should happen, but doesn't belong in the | 37 | * DeInitialization code that should happen, but doesn't belong in the |
38 | * destructor. | 38 | * destructor. |
39 | *@returns true means everything worked, false means failure, but is | 39 | *@returns true means everything worked, false means failure, but is |
40 | * meaningless. | 40 | * meaningless. |
41 | */ | 41 | */ |
42 | virtual bool deInit()=0; | 42 | virtual bool deInit()=0; |
43 | 43 | ||
44 | /** | 44 | /** |
45 | * Executed once per link per chain pass. Contains the guts of the program. | 45 | * Executed once per link per chain pass. Contains the guts of the program. |
46 | *@returns true if everything went well. A false value will halt the chain. | 46 | *@returns true if everything went well. A false value will halt the chain. |
47 | */ | 47 | */ |
48 | virtual bool timeSlice()=0; | 48 | virtual bool timeSlice()=0; |
49 | 49 | ||
50 | /** | 50 | /** |
51 | * This must be handled in order to process Instant Response Messages. | 51 | * This must be handled in order to process Instant Response Messages. |
52 | * This function should return null on all messages that it doesn't | 52 | * This function should return null on all messages that it doesn't |
53 | * understand how to handle, and construct new messages to return to sender | 53 | * understand how to handle, and construct new messages to return to sender |
54 | * in the cases where it does understand. | 54 | * in the cases where it does understand. |
55 | *@param pMsgIn The message that must be processed. | 55 | *@param pMsgIn The message that must be processed. |
56 | *@returns Either a new message in cases where a response is required, | 56 | *@returns Either a new message in cases where a response is required, |
57 | * or null if nothing needs to be done by this link. | 57 | * or null if nothing needs to be done by this link. |
58 | */ | 58 | */ |
59 | virtual LinkMessage *processIRM( LinkMessage *pMsgIn ) = 0; | 59 | virtual LinkMessage *processIRM( LinkMessage *pMsgIn ) = 0; |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * Broadcast a LinkMessage to all other links in the system. Each other | 62 | * Broadcast a LinkMessage to all other links in the system. Each other |
63 | * link will get a call of their processIRM function. If the message gets | 63 | * link will get a call of their processIRM function. If the message gets |
64 | * a response then you will regain control immediately, otherwise the system | 64 | * a response then you will regain control immediately, otherwise the system |
65 | * will give all other Links a chance to respond before returning NULL. | 65 | * will give all other Links a chance to respond before returning NULL. |
66 | *@param pMsgOut The message to broadcast. | 66 | *@param pMsgOut The message to broadcast. |
67 | *@returns The message response, or NULL if no Link understood your message. | 67 | *@returns The message response, or NULL if no Link understood your message. |
68 | */ | 68 | */ |
69 | LinkMessage *sendIRM( LinkMessage *pMsgOut ); | 69 | LinkMessage *sendIRM( LinkMessage *pMsgOut ); |
70 | 70 | ||
71 | private: | 71 | private: |
72 | /** | 72 | /** |
73 | * Set which chain we're assosiated with. This is how IRM messages make | 73 | * Set which chain we're assosiated with. This is how IRM messages make |
74 | * it out to the rest of the world. | 74 | * it out to the rest of the world. |
75 | *@param pNewChain A pointer to the containing program chain. | 75 | *@param pNewChain A pointer to the containing program chain. |
76 | */ | 76 | */ |
77 | void setChain( class ProgramChain *pNewChain ); | 77 | void setChain( class ProgramChain *pNewChain ); |
78 | 78 | ||
79 | /** | 79 | /** |
80 | * The pointer to the containing chain. | 80 | * The pointer to the containing chain. |
81 | */ | 81 | */ |
82 | class ProgramChain *pChain; | 82 | class ProgramChain *pChain; |
83 | /* | 83 | /* |
84 | void postMessage( LinkMessage *pMsg, int nLvl ); | 84 | void postMessage( LinkMessage *pMsg, int nLvl ); |
85 | LinkMessage *getMessage( int nLvl ); | 85 | LinkMessage *getMessage( int nLvl ); |
86 | 86 | ||
87 | enum | 87 | enum |
88 | { | 88 | { |
89 | msgToChain, | 89 | msgToChain, |
90 | msgToLink | 90 | msgToLink |
91 | }; | 91 | }; |
92 | 92 | ||
93 | private: | 93 | private: |
94 | Queue qMsgToChain; | 94 | Queue qMsgToChain; |
95 | Queue qMsgToLink; | 95 | Queue qMsgToLink; |
96 | */ | 96 | */ |
97 | }; | 97 | }; |
98 | } | ||
98 | 99 | ||
99 | #endif | 100 | #endif |
diff --git a/src/protocol.cpp b/src/protocol.cpp index 78b3ee2..0976b3b 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp | |||
@@ -1,20 +1,12 @@ | |||
1 | #include "protocol.h" | 1 | #include "bu/protocol.h" |
2 | 2 | ||
3 | Protocol::Protocol() | 3 | using namespace Bu; |
4 | { | ||
5 | pConnection = NULL; | ||
6 | } | ||
7 | 4 | ||
8 | Protocol::~Protocol() | 5 | Bu::Protocol::Protocol() |
9 | { | 6 | { |
10 | } | 7 | } |
11 | 8 | ||
12 | void Protocol::setConnection( Connection *pNewConnection ) | 9 | Bu::Protocol::~Protocol() |
13 | { | 10 | { |
14 | pConnection = pNewConnection; | ||
15 | } | 11 | } |
16 | 12 | ||
17 | Connection *Protocol::getConnection() | ||
18 | { | ||
19 | return pConnection; | ||
20 | } | ||
diff --git a/src/protocol.h b/src/protocol.h index 09e1c98..bca337f 100644 --- a/src/protocol.h +++ b/src/protocol.h | |||
@@ -1,62 +1,27 @@ | |||
1 | #ifndef PROTOCOL_H | 1 | #ifndef BU_PROTOCOL_H |
2 | #define PROTOCOL_H | 2 | #define BU_PROTOCOL_H |
3 | 3 | ||
4 | #include "connection.h" | 4 | #include <stdint.h> |
5 | 5 | ||
6 | /** This is the template for a class that handles specialized input and output | 6 | namespace Bu |
7 | * to connections of different types with different protocols. | ||
8 | *@author Mike Buland | ||
9 | */ | ||
10 | class Protocol | ||
11 | { | 7 | { |
12 | public: | 8 | class Client; |
13 | /** Constructor */ | ||
14 | Protocol(); | ||
15 | /** Deconstructor */ | ||
16 | virtual ~Protocol(); | ||
17 | 9 | ||
18 | /** | 10 | /** |
19 | * Function is called every time there is new data on the line. This is | 11 | * |
20 | * called directly from the Connection class to process data. This is not | ||
21 | * called whever there is pending data on the input, but every time new data | ||
22 | * is added to the input buffer. | ||
23 | *@returns True if processing went alright, false if something went wrong, | ||
24 | * I suppose. In truth this value is thrown away right now. | ||
25 | *@todo Either make a return value of false mean something, or make these | ||
26 | * void. | ||
27 | */ | 12 | */ |
28 | virtual bool onNewData()=0; | 13 | class Protocol |
14 | { | ||
15 | public: | ||
16 | Protocol(); | ||
17 | virtual ~Protocol(); | ||
29 | 18 | ||
30 | /** | 19 | virtual void onNewConnection( Bu::Client *pClient )=0; |
31 | * Function is called when there is a new connection. This should only | 20 | virtual void onNewData( Bu::Client *pClient )=0; |
32 | * happen once per Protocol object, but gives each protocol object a | ||
33 | * chance to perform connection handshaking and initialization at a point | ||
34 | * where they know that they have a handle to an active Connection. | ||
35 | *@returns See onNewData | ||
36 | */ | ||
37 | virtual bool onNewConnection()=0; | ||
38 | |||
39 | virtual void onNewClientConnection(){}; | ||
40 | 21 | ||
41 | virtual void poll(){}; | 22 | private: |
42 | |||
43 | /** | ||
44 | * Sets the Protocol's Connection object. This is rather important, and | ||
45 | * handled usually by the ConnectionManager. | ||
46 | *@param pNewConnection The Connection object that this protocol will use to | ||
47 | * deal with the outside world. | ||
48 | */ | ||
49 | void setConnection( class Connection *pNewConnection ); | ||
50 | |||
51 | /** | ||
52 | * Get a pointer to this object's Connection object, or NULL if one was | ||
53 | * never set. If used with the ConnectionManager that should never happen. | ||
54 | *@returns A pointer to the active Connection. | ||
55 | */ | ||
56 | Connection *getConnection(); | ||
57 | 23 | ||
58 | private: | 24 | }; |
59 | class Connection *pConnection; /**< The pointer to the Connection. */ | 25 | } |
60 | }; | ||
61 | 26 | ||
62 | #endif | 27 | #endif |
diff --git a/src/ringbuffer.cpp b/src/ringbuffer.cpp new file mode 100644 index 0000000..feb9bc7 --- /dev/null +++ b/src/ringbuffer.cpp | |||
@@ -0,0 +1,2 @@ | |||
1 | #include "bu/ringbuffer.h" | ||
2 | |||
diff --git a/src/ringbuffer.h b/src/ringbuffer.h new file mode 100644 index 0000000..be80e2f --- /dev/null +++ b/src/ringbuffer.h | |||
@@ -0,0 +1,97 @@ | |||
1 | #ifndef BU_RING_BUFFER_H | ||
2 | #define BU_RING_BUFFER_H | ||
3 | |||
4 | #include <memory> | ||
5 | #include "bu/exceptionbase.h" | ||
6 | |||
7 | namespace Bu | ||
8 | { | ||
9 | template<typename value, typename valuealloc=std::allocator<value> > | ||
10 | class RingBuffer | ||
11 | { | ||
12 | public: | ||
13 | RingBuffer( int nCapacity ) : | ||
14 | nCapacity( nCapacity ), | ||
15 | nStart( -1 ), | ||
16 | nEnd( -2 ) | ||
17 | { | ||
18 | aData = va.allocate( nCapacity ); | ||
19 | } | ||
20 | |||
21 | virtual ~RingBuffer() | ||
22 | { | ||
23 | for( int j = nStart; j < nEnd; j=(j+1%nCapacity) ) | ||
24 | { | ||
25 | va.destroy( &aData[j] ); | ||
26 | } | ||
27 | va.deallocate( aData, nCapacity ); | ||
28 | } | ||
29 | |||
30 | int getCapacity() | ||
31 | { | ||
32 | return nCapacity; | ||
33 | } | ||
34 | |||
35 | bool isFilled() | ||
36 | { | ||
37 | return (nStart == nEnd); | ||
38 | } | ||
39 | |||
40 | bool isEmpty() | ||
41 | { | ||
42 | return (nStart == -1); | ||
43 | } | ||
44 | |||
45 | void enqueue( const value &v ) | ||
46 | { | ||
47 | if( nStart == -1 ) | ||
48 | { | ||
49 | nStart = 0; | ||
50 | nEnd = 1; | ||
51 | va.construct( &aData[0], v ); | ||
52 | } | ||
53 | else if( nStart == nEnd ) | ||
54 | { | ||
55 | throw ExceptionBase("Hey, it's full!"); | ||
56 | } | ||
57 | else | ||
58 | { | ||
59 | va.construct( &aData[nEnd], v ); | ||
60 | nEnd = (nEnd+1)%nCapacity; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | value dequeue() | ||
65 | { | ||
66 | if( nStart == -1 ) | ||
67 | { | ||
68 | throw ExceptionBase("No data"); | ||
69 | } | ||
70 | else | ||
71 | { | ||
72 | value &v = aData[nStart]; | ||
73 | va.destroy( &aData[nStart] ); | ||
74 | nStart = (nStart+1)%nCapacity; | ||
75 | if( nStart == nEnd ) | ||
76 | { | ||
77 | nStart = -1; | ||
78 | nEnd = -2; | ||
79 | } | ||
80 | return v; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | value &operator[]( int nIndex ) | ||
85 | { | ||
86 | return aData[(nIndex+nStart)%nCapacity]; | ||
87 | } | ||
88 | |||
89 | private: | ||
90 | int nCapacity; | ||
91 | value *aData; | ||
92 | valuealloc va; | ||
93 | int nStart, nEnd; | ||
94 | }; | ||
95 | } | ||
96 | |||
97 | #endif | ||
diff --git a/src/serializable.cpp b/src/serializable.cpp deleted file mode 100644 index fd50943..0000000 --- a/src/serializable.cpp +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | #include "serializable.h" | ||
2 | |||
3 | Serializable::Serializable() | ||
4 | { | ||
5 | } | ||
6 | Serializable::~Serializable() | ||
7 | { | ||
8 | } | ||
diff --git a/src/serializable.h b/src/serializable.h deleted file mode 100644 index 06def29..0000000 --- a/src/serializable.h +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | #ifndef SERIALIZER_H | ||
2 | #define SERIALIZER_H | ||
3 | |||
4 | //#include "serializer.h" | ||
5 | |||
6 | /** | ||
7 | * The base class for any class you want to serialize. Simply include this as | ||
8 | * a base class, implement the purely virtual serialize function and you've got | ||
9 | * an easily serializable class. | ||
10 | */ | ||
11 | class Serializable | ||
12 | { | ||
13 | public: | ||
14 | /** | ||
15 | * Does nothing, here for completeness. | ||
16 | */ | ||
17 | Serializable(); | ||
18 | |||
19 | /** | ||
20 | * Here to ensure the deconstructor is virtual. | ||
21 | */ | ||
22 | virtual ~Serializable(); | ||
23 | |||
24 | /** | ||
25 | * This is the main workhorse of the serialization system, just override and | ||
26 | * you've got a serializable class. A reference to the Serializer archive | ||
27 | * used is passed in as your only parameter, query it to discover if you are | ||
28 | * loading or saving. | ||
29 | * @param ar A reference to the Serializer object to use. | ||
30 | */ | ||
31 | virtual void serialize( class Serializer &ar )=0; | ||
32 | }; | ||
33 | |||
34 | #endif | ||
diff --git a/src/serializer.cpp b/src/serializer.cpp deleted file mode 100644 index 636224e..0000000 --- a/src/serializer.cpp +++ /dev/null | |||
@@ -1,338 +0,0 @@ | |||
1 | #include "serializer.h" | ||
2 | #include "serializable.h" | ||
3 | #include <list> | ||
4 | |||
5 | Serializer::Serializer(bool bLoading): | ||
6 | bLoading(bLoading) | ||
7 | { | ||
8 | } | ||
9 | Serializer::~Serializer() | ||
10 | { | ||
11 | } | ||
12 | |||
13 | bool Serializer::isLoading() | ||
14 | { | ||
15 | return bLoading; | ||
16 | } | ||
17 | Serializer &Serializer::operator<<(bool p) | ||
18 | { | ||
19 | write( &p, sizeof(p) ); | ||
20 | return *this; | ||
21 | } | ||
22 | Serializer &Serializer::operator<<(int8_t p) | ||
23 | { | ||
24 | write( &p, sizeof(p) ); | ||
25 | return *this; | ||
26 | } | ||
27 | Serializer &Serializer::operator<<(int16_t p) | ||
28 | { | ||
29 | write( &p, sizeof(p) ); | ||
30 | return *this; | ||
31 | } | ||
32 | Serializer &Serializer::operator<<(int32_t p) | ||
33 | { | ||
34 | write( &p, sizeof(p) ); | ||
35 | return *this; | ||
36 | } | ||
37 | Serializer &Serializer::operator<<(int64_t p) | ||
38 | { | ||
39 | write( &p, sizeof(p) ); | ||
40 | return *this; | ||
41 | } | ||
42 | Serializer &Serializer::operator<<(uint8_t p) | ||
43 | { | ||
44 | write( &p, sizeof(p) ); | ||
45 | return *this; | ||
46 | } | ||
47 | Serializer &Serializer::operator<<(uint16_t p) | ||
48 | { | ||
49 | write( &p, sizeof(p) ); | ||
50 | return *this; | ||
51 | } | ||
52 | Serializer &Serializer::operator<<(uint32_t p) | ||
53 | { | ||
54 | write( &p, sizeof(p) ); | ||
55 | return *this; | ||
56 | } | ||
57 | Serializer &Serializer::operator<<(uint64_t p) | ||
58 | { | ||
59 | write( &p, sizeof(p) ); | ||
60 | return *this; | ||
61 | } | ||
62 | Serializer &Serializer::operator<<(long p) | ||
63 | { | ||
64 | write( &p, sizeof(p) ); | ||
65 | return *this; | ||
66 | } | ||
67 | Serializer &Serializer::operator<<(float p) | ||
68 | { | ||
69 | write( &p, sizeof(p) ); | ||
70 | return *this; | ||
71 | } | ||
72 | Serializer &Serializer::operator<<(double p) | ||
73 | { | ||
74 | write( &p, sizeof(p) ); | ||
75 | return *this; | ||
76 | } | ||
77 | Serializer &Serializer::operator<<(long double p) | ||
78 | { | ||
79 | write( &p, sizeof(p) ); | ||
80 | return *this; | ||
81 | } | ||
82 | |||
83 | Serializer &Serializer::operator>>(bool &p) | ||
84 | { | ||
85 | read( &p, sizeof(p) ); | ||
86 | return *this; | ||
87 | } | ||
88 | Serializer &Serializer::operator>>(int8_t &p) | ||
89 | { | ||
90 | read( &p, sizeof(p) ); | ||
91 | return *this; | ||
92 | } | ||
93 | Serializer &Serializer::operator>>(int16_t &p) | ||
94 | { | ||
95 | read( &p, sizeof(p) ); | ||
96 | return *this; | ||
97 | } | ||
98 | Serializer &Serializer::operator>>(int32_t &p) | ||
99 | { | ||
100 | read( &p, sizeof(p) ); | ||
101 | return *this; | ||
102 | } | ||
103 | Serializer &Serializer::operator>>(int64_t &p) | ||
104 | { | ||
105 | read( &p, sizeof(p) ); | ||
106 | return *this; | ||
107 | } | ||
108 | Serializer &Serializer::operator>>(uint8_t &p) | ||
109 | { | ||
110 | read( &p, sizeof(p) ); | ||
111 | return *this; | ||
112 | } | ||
113 | Serializer &Serializer::operator>>(uint16_t &p) | ||
114 | { | ||
115 | read( &p, sizeof(p) ); | ||
116 | return *this; | ||
117 | } | ||
118 | Serializer &Serializer::operator>>(uint32_t &p) | ||
119 | { | ||
120 | read( &p, sizeof(p) ); | ||
121 | return *this; | ||
122 | } | ||
123 | Serializer &Serializer::operator>>(uint64_t &p) | ||
124 | { | ||
125 | read( &p, sizeof(p) ); | ||
126 | return *this; | ||
127 | } | ||
128 | Serializer &Serializer::operator>>(long &p) | ||
129 | { | ||
130 | read( &p, sizeof(p) ); | ||
131 | return *this; | ||
132 | } | ||
133 | Serializer &Serializer::operator>>(float &p) | ||
134 | { | ||
135 | read( &p, sizeof(p) ); | ||
136 | return *this; | ||
137 | } | ||
138 | Serializer &Serializer::operator>>(double &p) | ||
139 | { | ||
140 | read( &p, sizeof(p) ); | ||
141 | return *this; | ||
142 | } | ||
143 | Serializer &Serializer::operator>>(long double &p) | ||
144 | { | ||
145 | read( &p, sizeof(p) ); | ||
146 | return *this; | ||
147 | } | ||
148 | |||
149 | Serializer &Serializer::operator&&(bool &p) | ||
150 | { | ||
151 | if (bLoading) | ||
152 | { | ||
153 | return *this >> p; | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | return *this << p; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | Serializer &Serializer::operator&&(int8_t &p) | ||
162 | { | ||
163 | if (bLoading) | ||
164 | { | ||
165 | return *this >> p; | ||
166 | } | ||
167 | else | ||
168 | { | ||
169 | return *this << p; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | Serializer &Serializer::operator&&(int16_t &p) | ||
174 | { | ||
175 | if (bLoading) | ||
176 | { | ||
177 | return *this >> p; | ||
178 | } | ||
179 | else | ||
180 | { | ||
181 | return *this << p; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | Serializer &Serializer::operator&&(int32_t &p) | ||
186 | { | ||
187 | if (bLoading) | ||
188 | { | ||
189 | return *this >> p; | ||
190 | } | ||
191 | else | ||
192 | { | ||
193 | return *this << p; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | Serializer &Serializer::operator&&(int64_t &p) | ||
198 | { | ||
199 | if (bLoading) | ||
200 | { | ||
201 | return *this >> p; | ||
202 | } | ||
203 | else | ||
204 | { | ||
205 | return *this << p; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | Serializer &Serializer::operator&&(uint8_t &p) | ||
210 | { | ||
211 | if (bLoading) | ||
212 | { | ||
213 | return *this >> p; | ||
214 | } | ||
215 | else | ||
216 | { | ||
217 | return *this << p; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | Serializer &Serializer::operator&&(uint16_t &p) | ||
222 | { | ||
223 | if (bLoading) | ||
224 | { | ||
225 | return *this >> p; | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | return *this << p; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | Serializer &Serializer::operator&&(uint32_t &p) | ||
234 | { | ||
235 | if (bLoading) | ||
236 | { | ||
237 | return *this >> p; | ||
238 | } | ||
239 | else | ||
240 | { | ||
241 | return *this << p; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | Serializer &Serializer::operator&&(uint64_t &p) | ||
246 | { | ||
247 | if (bLoading) | ||
248 | { | ||
249 | return *this >> p; | ||
250 | } | ||
251 | else | ||
252 | { | ||
253 | return *this << p; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | Serializer &Serializer::operator&&(float &p) | ||
258 | { | ||
259 | if (bLoading) | ||
260 | { | ||
261 | return *this >> p; | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | return *this << p; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | Serializer &Serializer::operator&&(double &p) | ||
270 | { | ||
271 | if (bLoading) | ||
272 | { | ||
273 | return *this >> p; | ||
274 | } | ||
275 | else | ||
276 | { | ||
277 | return *this << p; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | Serializer &Serializer::operator&&(long double &p) | ||
282 | { | ||
283 | if (bLoading) | ||
284 | { | ||
285 | return *this >> p; | ||
286 | } | ||
287 | else | ||
288 | { | ||
289 | return *this << p; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | |||
294 | Serializer &operator<<(Serializer &s, Serializable &p) | ||
295 | { | ||
296 | p.serialize( s ); | ||
297 | return s; | ||
298 | } | ||
299 | |||
300 | Serializer &operator>>(Serializer &s, Serializable &p) | ||
301 | { | ||
302 | p.serialize( s ); | ||
303 | return s; | ||
304 | } | ||
305 | |||
306 | Serializer &operator&&(Serializer &s, Serializable &p) | ||
307 | { | ||
308 | if (s.isLoading()) | ||
309 | { | ||
310 | return s >> p; | ||
311 | } | ||
312 | else | ||
313 | { | ||
314 | return s << p; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | Serializer &operator<<( Serializer &ar, std::string &s ) | ||
319 | { | ||
320 | ar << (uint32_t)s.length(); | ||
321 | ar.write( s.c_str(), s.length() ); | ||
322 | |||
323 | return ar; | ||
324 | } | ||
325 | |||
326 | Serializer &operator>>( Serializer &ar, std::string &s ) | ||
327 | { | ||
328 | uint32_t l; | ||
329 | ar >> l; | ||
330 | char *tmp = new char[l+1]; | ||
331 | tmp[l] = '\0'; | ||
332 | ar.read( tmp, l ); | ||
333 | s = tmp; | ||
334 | delete[] tmp; | ||
335 | |||
336 | return ar; | ||
337 | } | ||
338 | |||
diff --git a/src/serializer.h b/src/serializer.h deleted file mode 100644 index 3af489c..0000000 --- a/src/serializer.h +++ /dev/null | |||
@@ -1,80 +0,0 @@ | |||
1 | #ifndef SERIALIZABLE_H | ||
2 | #define SERIALIZABLE_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include <string> | ||
6 | #include <list> | ||
7 | //#include "serializable.h" | ||
8 | |||
9 | class Serializer | ||
10 | { | ||
11 | private: | ||
12 | bool bLoading; | ||
13 | public: | ||
14 | bool isLoading(); | ||
15 | |||
16 | enum | ||
17 | { | ||
18 | load = true, | ||
19 | save = false | ||
20 | }; | ||
21 | |||
22 | Serializer(bool bLoading); | ||
23 | virtual ~Serializer(); | ||
24 | virtual void close()=0; | ||
25 | |||
26 | virtual void write(const void *, int32_t)=0; | ||
27 | virtual void read(void *, int32_t)=0; | ||
28 | |||
29 | virtual Serializer &operator<<(bool); | ||
30 | virtual Serializer &operator<<(int8_t); | ||
31 | virtual Serializer &operator<<(int16_t); | ||
32 | virtual Serializer &operator<<(int32_t); | ||
33 | virtual Serializer &operator<<(int64_t); | ||
34 | virtual Serializer &operator<<(uint8_t); | ||
35 | virtual Serializer &operator<<(uint16_t); | ||
36 | virtual Serializer &operator<<(uint32_t); | ||
37 | virtual Serializer &operator<<(uint64_t); | ||
38 | virtual Serializer &operator<<(long); | ||
39 | virtual Serializer &operator<<(float); | ||
40 | virtual Serializer &operator<<(double); | ||
41 | virtual Serializer &operator<<(long double); | ||
42 | |||
43 | virtual Serializer &operator>>(bool &); | ||
44 | virtual Serializer &operator>>(int8_t &); | ||
45 | virtual Serializer &operator>>(int16_t &); | ||
46 | virtual Serializer &operator>>(int32_t &); | ||
47 | virtual Serializer &operator>>(int64_t &); | ||
48 | virtual Serializer &operator>>(uint8_t &); | ||
49 | virtual Serializer &operator>>(uint16_t &); | ||
50 | virtual Serializer &operator>>(uint32_t &); | ||
51 | virtual Serializer &operator>>(uint64_t &); | ||
52 | virtual Serializer &operator>>(long &); | ||
53 | virtual Serializer &operator>>(float &); | ||
54 | virtual Serializer &operator>>(double &); | ||
55 | virtual Serializer &operator>>(long double &); | ||
56 | |||
57 | virtual Serializer &operator&&(bool &); | ||
58 | virtual Serializer &operator&&(int8_t &); | ||
59 | virtual Serializer &operator&&(int16_t &); | ||
60 | virtual Serializer &operator&&(int32_t &); | ||
61 | virtual Serializer &operator&&(int64_t &); | ||
62 | virtual Serializer &operator&&(uint8_t &); | ||
63 | virtual Serializer &operator&&(uint16_t &); | ||
64 | virtual Serializer &operator&&(uint32_t &); | ||
65 | virtual Serializer &operator&&(uint64_t &); | ||
66 | virtual Serializer &operator&&(float &); | ||
67 | virtual Serializer &operator&&(double &); | ||
68 | virtual Serializer &operator&&(long double &); | ||
69 | |||
70 | //virtual Serializer &operator&(Serializable &); | ||
71 | }; | ||
72 | |||
73 | Serializer &operator<<(Serializer &, class Serializable &); | ||
74 | Serializer &operator>>(Serializer &, class Serializable &); | ||
75 | Serializer &operator&&(Serializer &s, class Serializable &p); | ||
76 | |||
77 | Serializer &operator<<(Serializer &, std::string &); | ||
78 | Serializer &operator>>(Serializer &, std::string &); | ||
79 | |||
80 | #endif | ||
diff --git a/src/server.cpp b/src/server.cpp new file mode 100644 index 0000000..d07a597 --- /dev/null +++ b/src/server.cpp | |||
@@ -0,0 +1,96 @@ | |||
1 | #include "bu/server.h" | ||
2 | #include <errno.h> | ||
3 | #include "bu/serversocket.h" | ||
4 | #include "bu/client.h" | ||
5 | #include "bu/socket.h" | ||
6 | |||
7 | Bu::Server::Server() : | ||
8 | nTimeoutSec( 0 ), | ||
9 | nTimeoutUSec( 0 ) | ||
10 | { | ||
11 | FD_ZERO( &fdActive ); | ||
12 | } | ||
13 | |||
14 | Bu::Server::~Server() | ||
15 | { | ||
16 | } | ||
17 | |||
18 | void Bu::Server::addPort( int nPort, int nPoolSize ) | ||
19 | { | ||
20 | ServerSocket *s = new ServerSocket( nPort, nPoolSize ); | ||
21 | int nSocket = s->getSocket(); | ||
22 | FD_SET( nSocket, &fdActive ); | ||
23 | hServers.insert( nSocket, s ); | ||
24 | } | ||
25 | |||
26 | void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize ) | ||
27 | { | ||
28 | ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); | ||
29 | int nSocket = s->getSocket(); | ||
30 | FD_SET( nSocket, &fdActive ); | ||
31 | hServers.insert( nSocket, s ); | ||
32 | } | ||
33 | |||
34 | void Bu::Server::setTimeout( int nTimeoutSec, int nTimeoutUSec ) | ||
35 | { | ||
36 | this->nTimeoutSec = nTimeoutSec; | ||
37 | this->nTimeoutUSec = nTimeoutUSec; | ||
38 | } | ||
39 | |||
40 | void Bu::Server::scan() | ||
41 | { | ||
42 | struct timeval xTimeout = { nTimeoutSec, nTimeoutUSec }; | ||
43 | |||
44 | fd_set fdRead = fdActive; | ||
45 | fd_set fdWrite = fdActive; | ||
46 | fd_set fdException = fdActive; | ||
47 | |||
48 | if( TEMP_FAILURE_RETRY( select( FD_SETSIZE, &fdRead, NULL, &fdException, &xTimeout ) ) < 0 ) | ||
49 | { | ||
50 | throw ExceptionBase("Error attempting to scan open connections."); | ||
51 | } | ||
52 | |||
53 | for( int j = 0; j < FD_SETSIZE; j++ ) | ||
54 | { | ||
55 | if( FD_ISSET( j, &fdRead ) ) | ||
56 | { | ||
57 | if( hServers.has( j ) ) | ||
58 | { | ||
59 | ServerSocket *pSrv = hServers.get( j ); | ||
60 | addClient( pSrv->accept(), pSrv->getPort() ); | ||
61 | } | ||
62 | else | ||
63 | { | ||
64 | Client *pClient = hClients.get( j ); | ||
65 | pClient->processInput(); | ||
66 | if( !pClient->isOpen() ) | ||
67 | { | ||
68 | onClosedConnection( pClient ); | ||
69 | hClients.erase( j ); | ||
70 | FD_CLR( j, &fdActive ); | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | // Now we just try to write all the pending data on all the sockets. | ||
77 | // this could be done better eventually, if we care about the socket | ||
78 | // wanting to accept writes (using a select). | ||
79 | for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ ) | ||
80 | { | ||
81 | (*i)->processOutput(); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | void Bu::Server::addClient( int nSocket, int nPort ) | ||
86 | { | ||
87 | FD_SET( nSocket, &fdActive ); | ||
88 | |||
89 | Client *c = new Client( | ||
90 | new Bu::Socket( nSocket ) | ||
91 | ); | ||
92 | hClients.insert( nSocket, c ); | ||
93 | |||
94 | onNewConnection( c, nPort ); | ||
95 | } | ||
96 | |||
diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..302b6e3 --- /dev/null +++ b/src/server.h | |||
@@ -0,0 +1,61 @@ | |||
1 | #ifndef BU_SERVER_H | ||
2 | #define BU_SERVER_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | #include "bu/fstring.h" | ||
7 | #include "bu/list.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | class ServerSocket; | ||
12 | class Socket; | ||
13 | class Client; | ||
14 | |||
15 | /** | ||
16 | * Core of a network server. This class is distinct from a ServerSocket in | ||
17 | * that a ServerSocket is one listening socket, nothing more. Socket will | ||
18 | * manage a pool of both ServerSockets and connected Sockets along with | ||
19 | * their protocols and buffers. | ||
20 | * | ||
21 | * To start serving on a new port, use the addPort functions. Each call to | ||
22 | * addPort creates a new ServerSocket, starts it listening, and adds it to | ||
23 | * the server pool. | ||
24 | * | ||
25 | * All of the real work is done by scan, which will wait for up | ||
26 | * to the timeout set by setTimeout before returning if there is no data | ||
27 | * pending. scan should probably be called in some sort of tight | ||
28 | * loop, possibly in it's own thread, or in the main control loop. | ||
29 | * | ||
30 | * In order to use a Server you must subclass it and implement the pure | ||
31 | * virtual functions. These allow you to receive notification of events | ||
32 | * happening within the server itself, and actually makes it useful. | ||
33 | */ | ||
34 | class Server | ||
35 | { | ||
36 | public: | ||
37 | Server(); | ||
38 | virtual ~Server(); | ||
39 | |||
40 | void addPort( int nPort, int nPoolSize=40 ); | ||
41 | void addPort( const FString &sAddr, int nPort, int nPoolSize=40 ); | ||
42 | |||
43 | void scan(); | ||
44 | void setTimeout( int nTimeoutSec, int nTimeoutUSec=0 ); | ||
45 | |||
46 | void addClient( int nSocket, int nPort ); | ||
47 | |||
48 | virtual void onNewConnection( Client *pClient, int nPort )=0; | ||
49 | virtual void onClosedConnection( Client *pClient )=0; | ||
50 | |||
51 | private: | ||
52 | int nTimeoutSec; | ||
53 | int nTimeoutUSec; | ||
54 | fd_set fdActive; | ||
55 | Hash<int,ServerSocket *> hServers; | ||
56 | typedef Hash<int,Client *> ClientHash; | ||
57 | ClientHash hClients; | ||
58 | }; | ||
59 | } | ||
60 | |||
61 | #endif | ||
diff --git a/src/serversocket.cpp b/src/serversocket.cpp new file mode 100644 index 0000000..1424630 --- /dev/null +++ b/src/serversocket.cpp | |||
@@ -0,0 +1,158 @@ | |||
1 | #include <time.h> | ||
2 | #include <string.h> | ||
3 | #include <stdio.h> | ||
4 | #include <errno.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <unistd.h> | ||
7 | #include <sys/types.h> | ||
8 | #include <sys/socket.h> | ||
9 | #include <termios.h> | ||
10 | #include <netinet/in.h> | ||
11 | #include <netdb.h> | ||
12 | #include <arpa/inet.h> | ||
13 | #include <fcntl.h> | ||
14 | #include "serversocket.h" | ||
15 | #include "exceptions.h" | ||
16 | |||
17 | Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) : | ||
18 | nPort( nPort ) | ||
19 | { | ||
20 | /* Create the socket and set it up to accept connections. */ | ||
21 | struct sockaddr_in name; | ||
22 | |||
23 | /* Give the socket a name. */ | ||
24 | name.sin_family = AF_INET; | ||
25 | name.sin_port = htons( nPort ); | ||
26 | |||
27 | // I think this specifies who we will accept connections from, | ||
28 | // a good thing to make configurable later on | ||
29 | name.sin_addr.s_addr = htonl( INADDR_ANY ); | ||
30 | |||
31 | startServer( name, nPoolSize ); | ||
32 | } | ||
33 | |||
34 | Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) : | ||
35 | nPort( nPort ) | ||
36 | { | ||
37 | /* Create the socket and set it up to accept connections. */ | ||
38 | struct sockaddr_in name; | ||
39 | |||
40 | /* Give the socket a name. */ | ||
41 | name.sin_family = AF_INET; | ||
42 | name.sin_port = htons( nPort ); | ||
43 | |||
44 | inet_aton( sAddr.getStr(), &name.sin_addr ); | ||
45 | |||
46 | startServer( name, nPoolSize ); | ||
47 | } | ||
48 | |||
49 | Bu::ServerSocket::~ServerSocket() | ||
50 | { | ||
51 | } | ||
52 | |||
53 | void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) | ||
54 | { | ||
55 | /* Create the socket. */ | ||
56 | nServer = socket( PF_INET, SOCK_STREAM, 0 ); | ||
57 | if( nServer < 0 ) | ||
58 | { | ||
59 | throw Bu::SocketException("Couldn't create a listen socket."); | ||
60 | } | ||
61 | |||
62 | int opt = 1; | ||
63 | setsockopt( | ||
64 | nServer, | ||
65 | SOL_SOCKET, | ||
66 | SO_REUSEADDR, | ||
67 | (char *)&opt, | ||
68 | sizeof( opt ) | ||
69 | ); | ||
70 | |||
71 | if( bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) | ||
72 | { | ||
73 | throw Bu::SocketException("Couldn't bind to the listen socket."); | ||
74 | } | ||
75 | |||
76 | if( listen( nServer, nPoolSize ) < 0 ) | ||
77 | { | ||
78 | throw Bu::SocketException( | ||
79 | "Couldn't begin listening to the server socket." | ||
80 | ); | ||
81 | } | ||
82 | |||
83 | FD_ZERO( &fdActive ); | ||
84 | /* Initialize the set of active sockets. */ | ||
85 | FD_SET( nServer, &fdActive ); | ||
86 | } | ||
87 | |||
88 | int Bu::ServerSocket::getSocket() | ||
89 | { | ||
90 | return nServer; | ||
91 | } | ||
92 | |||
93 | int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | ||
94 | { | ||
95 | fd_set fdRead = fdActive; | ||
96 | |||
97 | struct timeval xT; | ||
98 | |||
99 | xT.tv_sec = nTimeoutSec; | ||
100 | xT.tv_usec = nTimeoutUSec; | ||
101 | |||
102 | if( TEMP_FAILURE_RETRY(select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) | ||
103 | { | ||
104 | throw SocketException( | ||
105 | "Error scanning for new connections: %s", strerror( errno ) | ||
106 | ); | ||
107 | } | ||
108 | |||
109 | if( FD_ISSET( nServer, &fdRead ) ) | ||
110 | { | ||
111 | struct sockaddr_in clientname; | ||
112 | size_t size; | ||
113 | int nClient; | ||
114 | |||
115 | size = sizeof( clientname ); | ||
116 | #ifdef __CYGWIN__ | ||
117 | nClient = ::accept( nServer, (struct sockaddr *)&clientname, | ||
118 | (int *)&size | ||
119 | ); | ||
120 | #else | ||
121 | nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size ); | ||
122 | #endif | ||
123 | if( nClient < 0 ) | ||
124 | { | ||
125 | throw SocketException( | ||
126 | "Error accepting a new connection: %s", strerror( errno ) | ||
127 | ); | ||
128 | } | ||
129 | char tmpa[20]; | ||
130 | inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 ); | ||
131 | //"New connection from host %s, port %hd.", | ||
132 | // tmpa, ntohs (clientname.sin_port) ); | ||
133 | |||
134 | { | ||
135 | int flags; | ||
136 | |||
137 | flags = fcntl( nClient, F_GETFL, 0 ); | ||
138 | flags |= O_NONBLOCK; | ||
139 | if( fcntl( nClient, F_SETFL, flags ) < 0) | ||
140 | { | ||
141 | throw SocketException( | ||
142 | "Error setting option on client socket: %s", | ||
143 | strerror( errno ) | ||
144 | ); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | return nClient; | ||
149 | } | ||
150 | |||
151 | return -1; | ||
152 | } | ||
153 | |||
154 | int Bu::ServerSocket::getPort() | ||
155 | { | ||
156 | return nPort; | ||
157 | } | ||
158 | |||
diff --git a/src/serversocket.h b/src/serversocket.h new file mode 100644 index 0000000..b4ee247 --- /dev/null +++ b/src/serversocket.h | |||
@@ -0,0 +1,39 @@ | |||
1 | #ifndef BU_SERVER_SOCKET_H | ||
2 | #define BU_SERVER_SOCKET_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include "bu/fstring.h" | ||
6 | |||
7 | namespace Bu | ||
8 | { | ||
9 | /** | ||
10 | * A single tcp/ip server socket. When created the server socket will bind | ||
11 | * to the specified interface and port, and immediately begin listening for | ||
12 | * connections. When connections come in they are pooled by the networking | ||
13 | * drivers in the kernel until they are accepted, this means that failure | ||
14 | * to keep space in the connection pool will result in connection refusals. | ||
15 | * | ||
16 | * Although the accept function returns an integral file descriptor, it is | ||
17 | * designed to be used with the Socket class. | ||
18 | */ | ||
19 | class ServerSocket | ||
20 | { | ||
21 | public: | ||
22 | ServerSocket( int nPort, int nPoolSize=40 ); | ||
23 | ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); | ||
24 | virtual ~ServerSocket(); | ||
25 | |||
26 | int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); | ||
27 | int getSocket(); | ||
28 | int getPort(); | ||
29 | |||
30 | private: | ||
31 | void startServer( struct sockaddr_in &name, int nPoolSize ); | ||
32 | |||
33 | fd_set fdActive; | ||
34 | int nServer; | ||
35 | int nPort; | ||
36 | }; | ||
37 | } | ||
38 | |||
39 | #endif | ||
diff --git a/src/sfile.cpp b/src/sfile.cpp deleted file mode 100644 index f1de03c..0000000 --- a/src/sfile.cpp +++ /dev/null | |||
@@ -1,74 +0,0 @@ | |||
1 | #include "sfile.h" | ||
2 | #include "exceptions.h" | ||
3 | |||
4 | SFile::SFile( const char *sName, const char *sFlags ) | ||
5 | { | ||
6 | fh = fopen( sName, sFlags ); | ||
7 | } | ||
8 | |||
9 | SFile::~SFile() | ||
10 | { | ||
11 | } | ||
12 | |||
13 | void SFile::close() | ||
14 | { | ||
15 | if( fh ) | ||
16 | { | ||
17 | fclose( fh ); | ||
18 | fh = NULL; | ||
19 | } | ||
20 | } | ||
21 | |||
22 | size_t SFile::read( char *pBuf, size_t nBytes ) | ||
23 | { | ||
24 | if( !fh ) | ||
25 | throw FileException("File not open."); | ||
26 | |||
27 | return fread( pBuf, 1, nBytes, fh ); | ||
28 | } | ||
29 | |||
30 | size_t SFile::write( const char *pBuf, size_t nBytes ) | ||
31 | { | ||
32 | if( !fh ) | ||
33 | throw FileException("File not open."); | ||
34 | |||
35 | return fwrite( pBuf, 1, nBytes, fh ); | ||
36 | } | ||
37 | |||
38 | long SFile::tell() | ||
39 | { | ||
40 | if( !fh ) | ||
41 | throw FileException("File not open."); | ||
42 | |||
43 | return ftell( fh ); | ||
44 | } | ||
45 | |||
46 | void SFile::seek( long offset ) | ||
47 | { | ||
48 | if( !fh ) | ||
49 | throw FileException("File not open."); | ||
50 | |||
51 | fseek( fh, offset, SEEK_CUR ); | ||
52 | } | ||
53 | |||
54 | void SFile::setPos( long pos ) | ||
55 | { | ||
56 | if( !fh ) | ||
57 | throw FileException("File not open."); | ||
58 | |||
59 | fseek( fh, pos, SEEK_SET ); | ||
60 | } | ||
61 | |||
62 | void SFile::setPosEnd( long pos ) | ||
63 | { | ||
64 | if( !fh ) | ||
65 | throw FileException("File not open."); | ||
66 | |||
67 | fseek( fh, pos, SEEK_END ); | ||
68 | } | ||
69 | |||
70 | bool SFile::isEOS() | ||
71 | { | ||
72 | return feof( fh ); | ||
73 | } | ||
74 | |||
diff --git a/src/sfile.h b/src/sfile.h deleted file mode 100644 index b51e5bc..0000000 --- a/src/sfile.h +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | #ifndef SFILE_H | ||
2 | #define SFILE_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | #include "stream.h" | ||
7 | |||
8 | class SFile : public Stream | ||
9 | { | ||
10 | public: | ||
11 | SFile( const char *sName, const char *sFlags ); | ||
12 | virtual ~SFile(); | ||
13 | |||
14 | virtual void close(); | ||
15 | virtual size_t read( char *pBuf, size_t nBytes ); | ||
16 | virtual size_t write( const char *pBuf, size_t nBytes ); | ||
17 | |||
18 | virtual long tell(); | ||
19 | virtual void seek( long offset ); | ||
20 | virtual void setPos( long pos ); | ||
21 | virtual void setPosEnd( long pos ); | ||
22 | virtual bool isEOS(); | ||
23 | |||
24 | private: | ||
25 | FILE *fh; | ||
26 | |||
27 | }; | ||
28 | |||
29 | #endif | ||
diff --git a/src/singleton.h b/src/singleton.h index 47adbd5..c43d71b 100644 --- a/src/singleton.h +++ b/src/singleton.h | |||
@@ -1,59 +1,62 @@ | |||
1 | #ifndef SINGLETON_H | 1 | #ifndef BU_SINGLETON_H |
2 | #define SINGLETON_H | 2 | #define BU_SINGLETON_H |
3 | 3 | ||
4 | #include <stdio.h> | 4 | #include <stdio.h> |
5 | 5 | ||
6 | /** | 6 | namespace Bu |
7 | * Provides singleton functionality in a modular sort of way. Make this the | ||
8 | * base class of any other class and you immediately gain singleton | ||
9 | * functionality. Be sure to make your constructor and various functions use | ||
10 | * intellegent scoping. Cleanup and instantiation are performed automatically | ||
11 | * for you at first use and program exit. There are two things that you must | ||
12 | * do when using this template, first is to inherit from it with the name of | ||
13 | * your class filling in for T and then make this class a friend of your class. | ||
14 | *@code | ||
15 | * // Making the Single Singleton: | ||
16 | * class Single : public Singleton<Single> | ||
17 | * { | ||
18 | * friend class Singleton<Single>; | ||
19 | * protected: | ||
20 | * Single(); | ||
21 | * ... | ||
22 | * }; | ||
23 | @endcode | ||
24 | * You can still add public functions and variables to your new Singleton child | ||
25 | * class, but your constructor should be protected (hence the need for the | ||
26 | * friend decleration). | ||
27 | *@author Mike Buland | ||
28 | */ | ||
29 | template <class T> | ||
30 | class Singleton | ||
31 | { | 7 | { |
32 | protected: | ||
33 | /** | 8 | /** |
34 | * Private constructor. This constructor is empty but has a body so that | 9 | * Provides singleton functionality in a modular sort of way. Make this the |
35 | * you can make your own override of it. Be sure that you're override is | 10 | * base class of any other class and you immediately gain singleton |
36 | * also protected. | 11 | * functionality. Be sure to make your constructor and various functions use |
12 | * intellegent scoping. Cleanup and instantiation are performed automatically | ||
13 | * for you at first use and program exit. There are two things that you must | ||
14 | * do when using this template, first is to inherit from it with the name of | ||
15 | * your class filling in for T and then make this class a friend of your class. | ||
16 | *@code | ||
17 | * // Making the Single Singleton: | ||
18 | * class Single : public Singleton<Single> | ||
19 | * { | ||
20 | * friend class Singleton<Single>; | ||
21 | * protected: | ||
22 | * Single(); | ||
23 | * ... | ||
24 | * }; | ||
25 | @endcode | ||
26 | * You can still add public functions and variables to your new Singleton child | ||
27 | * class, but your constructor should be protected (hence the need for the | ||
28 | * friend decleration). | ||
29 | *@author Mike Buland | ||
37 | */ | 30 | */ |
38 | Singleton() {}; | 31 | template <class T> |
32 | class Singleton | ||
33 | { | ||
34 | protected: | ||
35 | /** | ||
36 | * Private constructor. This constructor is empty but has a body so that | ||
37 | * you can make your own override of it. Be sure that you're override is | ||
38 | * also protected. | ||
39 | */ | ||
40 | Singleton() {}; | ||
39 | 41 | ||
40 | private: | 42 | private: |
41 | /** | 43 | /** |
42 | * Copy constructor, defined so that you could write your own as well. | 44 | * Copy constructor, defined so that you could write your own as well. |
43 | */ | 45 | */ |
44 | Singleton( const Singleton& ); | 46 | Singleton( const Singleton& ); |
45 | 47 | ||
46 | public: | 48 | public: |
47 | /** | 49 | /** |
48 | * Get a handle to the contained instance of the contained class. It is | 50 | * Get a handle to the contained instance of the contained class. It is |
49 | * a reference. | 51 | * a reference. |
50 | *@returns A reference to the contained object. | 52 | *@returns A reference to the contained object. |
51 | */ | 53 | */ |
52 | static T &getInstance() | 54 | static T &getInstance() |
53 | { | 55 | { |
54 | static T i; | 56 | static T i; |
55 | return i; | 57 | return i; |
56 | } | 58 | } |
57 | }; | 59 | }; |
60 | } | ||
58 | 61 | ||
59 | #endif | 62 | #endif |
diff --git a/src/socket.cpp b/src/socket.cpp new file mode 100644 index 0000000..e567061 --- /dev/null +++ b/src/socket.cpp | |||
@@ -0,0 +1,294 @@ | |||
1 | #include <string.h> | ||
2 | #include <stdio.h> | ||
3 | #include <errno.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <unistd.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <sys/socket.h> | ||
8 | #include <sys/time.h> | ||
9 | #include <netinet/in.h> | ||
10 | #include <netdb.h> | ||
11 | #include <arpa/inet.h> | ||
12 | #include <errno.h> | ||
13 | #include <fcntl.h> | ||
14 | #include "socket.h" | ||
15 | #include "exceptions.h" | ||
16 | |||
17 | #define RBS (1024*2) | ||
18 | |||
19 | Bu::Socket::Socket( int nSocket ) : | ||
20 | nSocket( nSocket ), | ||
21 | bActive( true ) | ||
22 | { | ||
23 | } | ||
24 | |||
25 | Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) | ||
26 | { | ||
27 | struct sockaddr_in xServerName; | ||
28 | bActive = false; | ||
29 | |||
30 | /* Create the socket. */ | ||
31 | nSocket = socket( PF_INET, SOCK_STREAM, 0 ); | ||
32 | |||
33 | if( nSocket < 0 ) | ||
34 | { | ||
35 | throw ExceptionBase("Couldn't create socket.\n"); | ||
36 | } | ||
37 | |||
38 | // These lines set the socket to non-blocking, a good thing? | ||
39 | int flags; | ||
40 | flags = fcntl(nSocket, F_GETFL, 0); | ||
41 | flags |= O_NONBLOCK; | ||
42 | if (fcntl(nSocket, F_SETFL, flags) < 0) | ||
43 | { | ||
44 | throw ExceptionBase("Couldn't set socket options.\n"); | ||
45 | } | ||
46 | |||
47 | /* Connect to the server. */ | ||
48 | //printf("Resolving hostname (%s)...\n", sAddr ); | ||
49 | { | ||
50 | struct hostent *hostinfo; | ||
51 | |||
52 | xServerName.sin_family = AF_INET; | ||
53 | xServerName.sin_port = htons( nPort ); | ||
54 | hostinfo = gethostbyname( sAddr.getStr() ); | ||
55 | if (hostinfo == NULL) | ||
56 | { | ||
57 | throw ExceptionBase("Couldn't resolve hostname.\n"); | ||
58 | } | ||
59 | xServerName.sin_addr = *(struct in_addr *) hostinfo->h_addr; | ||
60 | } | ||
61 | |||
62 | //printf("Making actual connection..."); | ||
63 | //fflush( stdout ); | ||
64 | connect( | ||
65 | nSocket, | ||
66 | (struct sockaddr *)&xServerName, | ||
67 | sizeof(xServerName) | ||
68 | ); | ||
69 | //printf("Connected.\n"); | ||
70 | |||
71 | bActive = true; | ||
72 | |||
73 | if( nTimeout > 0 ) | ||
74 | { | ||
75 | fd_set rfds, wfds, efds; | ||
76 | int retval; | ||
77 | |||
78 | FD_ZERO(&rfds); | ||
79 | FD_SET(nSocket, &rfds); | ||
80 | FD_ZERO(&wfds); | ||
81 | FD_SET(nSocket, &wfds); | ||
82 | FD_ZERO(&efds); | ||
83 | FD_SET(nSocket, &efds); | ||
84 | |||
85 | struct timeval tv; | ||
86 | tv.tv_sec = nTimeout; | ||
87 | tv.tv_usec = 0; | ||
88 | |||
89 | retval = select( nSocket+1, &rfds, &wfds, &efds, &tv ); | ||
90 | |||
91 | if( retval == 0 ) | ||
92 | { | ||
93 | close(); | ||
94 | throw ExceptionBase("Connection timeout.\n"); | ||
95 | } | ||
96 | |||
97 | } | ||
98 | } | ||
99 | |||
100 | Bu::Socket::~Socket() | ||
101 | { | ||
102 | } | ||
103 | |||
104 | void Bu::Socket::close() | ||
105 | { | ||
106 | if( bActive ) | ||
107 | { | ||
108 | fsync( nSocket ); | ||
109 | ::close( nSocket ); | ||
110 | } | ||
111 | bActive = false; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | void Bu::Socket::read() | ||
116 | { | ||
117 | char buffer[RBS]; | ||
118 | int nbytes; | ||
119 | int nTotalRead=0; | ||
120 | |||
121 | for(;;) | ||
122 | { | ||
123 | //memset( buffer, 0, RBS ); | ||
124 | |||
125 | nbytes = ::read( nSocket, buffer, RBS ); | ||
126 | if( nbytes < 0 && errno != 0 && errno != EAGAIN ) | ||
127 | { | ||
128 | //printf("errno: %d, %s\n", errno, strerror( errno ) ); | ||
129 | //perror("readInput"); | ||
130 | throw ConnectionException( | ||
131 | excodeReadError, | ||
132 | "Read error: %s", | ||
133 | strerror( errno ) | ||
134 | ); | ||
135 | } | ||
136 | else | ||
137 | { | ||
138 | if( nbytes <= 0 ) | ||
139 | break; | ||
140 | nTotalRead += nbytes; | ||
141 | sReadBuf.append( buffer, nbytes ); | ||
142 | if( nbytes < RBS ) | ||
143 | { | ||
144 | break; | ||
145 | } | ||
146 | |||
147 | // New test, if data is divisible by RBS bytes on some libs the | ||
148 | // read could block, this keeps it from happening. | ||
149 | { | ||
150 | fd_set rfds; | ||
151 | FD_ZERO(&rfds); | ||
152 | FD_SET(nSocket, &rfds); | ||
153 | struct timeval tv = { 0, 0 }; | ||
154 | int retval = select( nSocket+1, &rfds, NULL, NULL, &tv ); | ||
155 | if( retval == -1 ) | ||
156 | throw ConnectionException( | ||
157 | excodeBadReadError, | ||
158 | "Bad Read error" | ||
159 | ); | ||
160 | if( !FD_ISSET( nSocket, &rfds ) ) | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | }*/ | ||
166 | |||
167 | size_t Bu::Socket::read( void *pBuf, size_t nBytes ) | ||
168 | { | ||
169 | int nRead = TEMP_FAILURE_RETRY( ::read( nSocket, pBuf, nBytes ) ); | ||
170 | if( nRead < 0 ) | ||
171 | { | ||
172 | throw ConnectionException( excodeReadError, strerror(errno) ); | ||
173 | } | ||
174 | return nRead; | ||
175 | } | ||
176 | |||
177 | //size_t Bu::Socket::read( void *pBuf, size_t nBytes, uint32_t nTimeout ) | ||
178 | //{ | ||
179 | //} | ||
180 | |||
181 | size_t Bu::Socket::write( const void *pBuf, size_t nBytes ) | ||
182 | { | ||
183 | int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) ); | ||
184 | if( nWrote < 0 ) | ||
185 | { | ||
186 | throw ConnectionException( excodeWriteError, strerror(errno) ); | ||
187 | } | ||
188 | return nWrote; | ||
189 | } | ||
190 | |||
191 | long Bu::Socket::tell() | ||
192 | { | ||
193 | throw UnsupportedException(); | ||
194 | } | ||
195 | |||
196 | void Bu::Socket::seek( long offset ) | ||
197 | { | ||
198 | throw UnsupportedException(); | ||
199 | } | ||
200 | |||
201 | void Bu::Socket::setPos( long pos ) | ||
202 | { | ||
203 | throw UnsupportedException(); | ||
204 | } | ||
205 | |||
206 | void Bu::Socket::setPosEnd( long pos ) | ||
207 | { | ||
208 | throw UnsupportedException(); | ||
209 | } | ||
210 | |||
211 | bool Bu::Socket::isEOS() | ||
212 | { | ||
213 | return !bActive; | ||
214 | } | ||
215 | |||
216 | bool Bu::Socket::canRead() | ||
217 | { | ||
218 | fd_set rfds; | ||
219 | FD_ZERO(&rfds); | ||
220 | FD_SET(nSocket, &rfds); | ||
221 | struct timeval tv = { 0, 0 }; | ||
222 | int retval = select( nSocket+1, &rfds, NULL, NULL, &tv ); | ||
223 | if( retval == -1 ) | ||
224 | throw ConnectionException( | ||
225 | excodeBadReadError, | ||
226 | "Bad Read error" | ||
227 | ); | ||
228 | if( !FD_ISSET( nSocket, &rfds ) ) | ||
229 | return false; | ||
230 | return true; | ||
231 | } | ||
232 | |||
233 | bool Bu::Socket::canWrite() | ||
234 | { | ||
235 | fd_set wfds; | ||
236 | FD_ZERO(&wfds); | ||
237 | FD_SET(nSocket, &wfds); | ||
238 | struct timeval tv = { 0, 0 }; | ||
239 | int retval = select( nSocket+1, NULL, &wfds, NULL, &tv ); | ||
240 | if( retval == -1 ) | ||
241 | throw ConnectionException( | ||
242 | excodeBadReadError, | ||
243 | "Bad Read error" | ||
244 | ); | ||
245 | if( !FD_ISSET( nSocket, &wfds ) ) | ||
246 | return false; | ||
247 | return true; | ||
248 | } | ||
249 | |||
250 | bool Bu::Socket::isReadable() | ||
251 | { | ||
252 | return true; | ||
253 | } | ||
254 | |||
255 | bool Bu::Socket::isWritable() | ||
256 | { | ||
257 | return true; | ||
258 | } | ||
259 | |||
260 | bool Bu::Socket::isSeekable() | ||
261 | { | ||
262 | return false; | ||
263 | } | ||
264 | |||
265 | bool Bu::Socket::isBlocking() | ||
266 | { | ||
267 | return false; | ||
268 | } | ||
269 | |||
270 | void Bu::Socket::setBlocking( bool bBlocking ) | ||
271 | { | ||
272 | } | ||
273 | |||
274 | void Bu::Socket::flush() | ||
275 | { | ||
276 | } | ||
277 | |||
278 | bool Bu::Socket::isOpen() | ||
279 | { | ||
280 | return bActive; | ||
281 | } | ||
282 | |||
283 | Bu::FString Bu::Socket::getAddress() const | ||
284 | { | ||
285 | struct sockaddr_in addr; | ||
286 | socklen_t len = sizeof(addr); | ||
287 | addr.sin_family = AF_INET; | ||
288 | getsockname( nSocket, (sockaddr *)(&addr), &len ); | ||
289 | char buf[150]; | ||
290 | sprintf( buf, "%s", inet_ntoa( addr.sin_addr ) ); | ||
291 | |||
292 | return buf; | ||
293 | } | ||
294 | |||
diff --git a/src/socket.h b/src/socket.h new file mode 100644 index 0000000..c291549 --- /dev/null +++ b/src/socket.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef BU_SOCKET_H | ||
2 | #define BU_SOCKET_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | #include "stream.h" | ||
7 | #include "fstring.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | /** | ||
12 | * | ||
13 | */ | ||
14 | class Socket : public Stream | ||
15 | { | ||
16 | public: | ||
17 | Socket( int nSocket ); | ||
18 | Socket( const FString &sAddr, int nPort, int nTimeout=30 ); | ||
19 | virtual ~Socket(); | ||
20 | |||
21 | virtual void close(); | ||
22 | //virtual void read(); | ||
23 | virtual size_t read( void *pBuf, size_t nBytes ); | ||
24 | virtual size_t read( void *pBuf, size_t nBytes, uint32_t nTimeout ); | ||
25 | virtual size_t write( const void *pBuf, size_t nBytes ); | ||
26 | |||
27 | virtual long tell(); | ||
28 | virtual void seek( long offset ); | ||
29 | virtual void setPos( long pos ); | ||
30 | virtual void setPosEnd( long pos ); | ||
31 | virtual bool isEOS(); | ||
32 | virtual bool isOpen(); | ||
33 | |||
34 | virtual void flush(); | ||
35 | |||
36 | virtual bool canRead(); | ||
37 | virtual bool canWrite(); | ||
38 | |||
39 | virtual bool isReadable(); | ||
40 | virtual bool isWritable(); | ||
41 | virtual bool isSeekable(); | ||
42 | |||
43 | virtual bool isBlocking(); | ||
44 | virtual void setBlocking( bool bBlocking=true ); | ||
45 | |||
46 | Bu::FString getAddress() const; | ||
47 | |||
48 | private: | ||
49 | int nSocket; | ||
50 | bool bActive; | ||
51 | FString sReadBuf; | ||
52 | }; | ||
53 | } | ||
54 | |||
55 | #endif | ||
diff --git a/src/sptr.cpp b/src/sptr.cpp index 7f5e894..8ea7f8f 100644 --- a/src/sptr.cpp +++ b/src/sptr.cpp | |||
@@ -1 +1 @@ | |||
#include "sptr.h" | #include "bu/sptr.h" | ||
@@ -1,144 +1,192 @@ | |||
1 | #ifndef SPTR_H | 1 | #ifndef BU_SPTR_H |
2 | #define SPTR_H | 2 | #define BU_SPTR_H |
3 | 3 | ||
4 | #include <stdint.h> | 4 | #include <stdint.h> |
5 | #include <stdio.h> | 5 | #include <stdio.h> |
6 | 6 | ||
7 | template<typename T> class SPtr; | 7 | namespace Bu |
8 | template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src ); | ||
9 | |||
10 | template<typename T> | ||
11 | class SPtr | ||
12 | { | 8 | { |
13 | template<typename Tb, typename Ta> | 9 | template<typename T> class SPtr; |
14 | friend SPtr<Tb> SPtrCast( SPtr<Ta> pt ); | 10 | template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src ); |
15 | public: | 11 | |
16 | SPtr() : | 12 | template<typename T> |
17 | pRefCnt( NULL ), | 13 | class SPtr |
18 | pData( NULL ) | 14 | { |
19 | { | 15 | template<typename Tb, typename Ta> |
20 | } | 16 | friend SPtr<Tb> SPtrCast( SPtr<Ta> pt ); |
17 | public: | ||
18 | SPtr() : | ||
19 | pRefCnt( NULL ), | ||
20 | pData( NULL ) | ||
21 | { | ||
22 | } | ||
21 | 23 | ||
22 | ~SPtr() | 24 | ~SPtr() |
23 | { | 25 | { |
24 | decCount(); | 26 | decCount(); |
25 | } | 27 | } |
26 | 28 | ||
27 | SPtr( const SPtr<T> &src ) : | 29 | SPtr( const SPtr<T> &src ) : |
28 | pRefCnt( src.pRefCnt ), | 30 | pRefCnt( src.pRefCnt ), |
29 | pData( src.pData ) | 31 | pData( src.pData ) |
30 | { | 32 | { |
31 | if( pRefCnt ) | 33 | if( pRefCnt ) |
32 | (*pRefCnt) += 1; | 34 | (*pRefCnt) += 1; |
33 | } | 35 | } |
34 | 36 | ||
35 | SPtr( T *pSrc ) : | 37 | SPtr( T *pSrc ) : |
36 | pRefCnt( NULL ), | 38 | pRefCnt( NULL ), |
37 | pData( pSrc ) | 39 | pData( pSrc ) |
38 | { | ||
39 | if( pData ) | ||
40 | { | 40 | { |
41 | pRefCnt = new int32_t; | 41 | if( pData ) |
42 | (*pRefCnt) = 1; | 42 | { |
43 | pRefCnt = new int32_t; | ||
44 | (*pRefCnt) = 1; | ||
45 | } | ||
43 | } | 46 | } |
44 | } | ||
45 | 47 | ||
46 | int32_t count() const | 48 | /** |
47 | { | 49 | * Get the number of references to this pointer. |
48 | return *pRefCnt; | 50 | *@returns (int32_t) The number of references to this pointer. |
49 | } | 51 | */ |
52 | int32_t count() const | ||
53 | { | ||
54 | return *pRefCnt; | ||
55 | } | ||
50 | 56 | ||
51 | const T *operator->() const | 57 | /** |
52 | { | 58 | * Pointer access operator. |
53 | return pData; | 59 | *@returns (const T *) |
54 | } | 60 | */ |
61 | const T *operator->() const | ||
62 | { | ||
63 | return pData; | ||
64 | } | ||
55 | 65 | ||
56 | const T &operator*() const | 66 | /** |
57 | { | 67 | * Dereference operator. |
58 | return *pData; | 68 | *@returns (const T &) The value at the end of the pointer. |
59 | } | 69 | */ |
60 | 70 | const T &operator*() const | |
61 | T *operator->() | 71 | { |
62 | { | 72 | return *pData; |
63 | return pData; | 73 | } |
64 | } | 74 | |
75 | /** | ||
76 | * Pointer access operator. | ||
77 | *@returns (T *) | ||
78 | */ | ||
79 | T *operator->() | ||
80 | { | ||
81 | return pData; | ||
82 | } | ||
65 | 83 | ||
66 | T &operator*() | 84 | /** |
67 | { | 85 | * Dereference operator. |
68 | return *pData; | 86 | *@returns (T &) The value at the end of the pointer. |
69 | } | 87 | */ |
88 | T &operator*() | ||
89 | { | ||
90 | return *pData; | ||
91 | } | ||
70 | 92 | ||
71 | SPtr<T> operator=( const SPtr<T> &src ) | 93 | /** |
72 | { | 94 | * Assignment operator. |
73 | decCount(); | 95 | *@param src (const SPtr<T> &) |
74 | pRefCnt = src.pRefCnt; | 96 | */ |
75 | pData = src.pData; | 97 | SPtr<T> operator=( const SPtr<T> &src ) |
76 | if( pRefCnt ) | 98 | { |
77 | (*pRefCnt) += 1; | 99 | decCount(); |
100 | pRefCnt = src.pRefCnt; | ||
101 | pData = src.pData; | ||
102 | if( pRefCnt ) | ||
103 | (*pRefCnt) += 1; | ||
78 | 104 | ||
79 | return *this; | 105 | return *this; |
80 | } | 106 | } |
81 | 107 | ||
82 | const SPtr<T> operator=( const SPtr<T> &src ) const | 108 | /** |
83 | { | 109 | * Assignment operator. |
84 | decCount(); | 110 | *@param src (const SPtr<T> &) |
85 | pRefCnt = src.pRefCnt; | 111 | */ |
86 | pData = src.pData; | 112 | const SPtr<T> operator=( const SPtr<T> &src ) const |
87 | if( pRefCnt ) | 113 | { |
88 | (*pRefCnt) += 1; | 114 | decCount(); |
115 | pRefCnt = src.pRefCnt; | ||
116 | pData = src.pData; | ||
117 | if( pRefCnt ) | ||
118 | (*pRefCnt) += 1; | ||
89 | 119 | ||
90 | return *this; | 120 | return *this; |
91 | } | 121 | } |
92 | 122 | ||
93 | bool operator==( const SPtr<T> &src ) const | 123 | /** |
94 | { | 124 | * Equals comparison operator. |
95 | return pData == src.pData; | 125 | *@param src (const SPtr<T> &) The SPtr to compare to. |
96 | } | 126 | *@returns (bool) Are the equal? |
127 | */ | ||
128 | bool operator==( const SPtr<T> &src ) const | ||
129 | { | ||
130 | return pData == src.pData; | ||
131 | } | ||
97 | 132 | ||
98 | bool operator==( const T *src ) const | 133 | /** |
99 | { | 134 | * Equals comparison operator. |
100 | return pData == src; | 135 | *@param src (const T *) The pointer to compare to. |
101 | } | 136 | *@returns (bool) Are the equal? |
137 | */ | ||
138 | bool operator==( const T *src ) const | ||
139 | { | ||
140 | return pData == src; | ||
141 | } | ||
102 | 142 | ||
103 | operator bool() const | 143 | /** |
104 | { | 144 | * Boolean cast operator. Do we have a pointer? |
105 | return pRefCnt != NULL; | 145 | */ |
106 | } | 146 | operator bool() const |
147 | { | ||
148 | return pRefCnt != NULL; | ||
149 | } | ||
107 | 150 | ||
108 | bool isSet() const | 151 | /** |
109 | { | 152 | * Do we have a pointer? |
110 | return pRefCnt != NULL; | 153 | *@returns (bool) Do we have a pointer? |
111 | } | 154 | */ |
155 | bool isSet() const | ||
156 | { | ||
157 | return pRefCnt != NULL; | ||
158 | } | ||
112 | 159 | ||
113 | private: | 160 | private: |
114 | void decCount() const | 161 | void decCount() const |
115 | { | ||
116 | if( pRefCnt ) | ||
117 | { | 162 | { |
118 | (*pRefCnt) -= 1; | 163 | if( pRefCnt ) |
119 | //printf("Decrementing ref-count to %d\n", *pRefCnt ); | ||
120 | if( (*pRefCnt) == 0 ) | ||
121 | { | 164 | { |
122 | delete pRefCnt; | 165 | (*pRefCnt) -= 1; |
123 | delete pData; | 166 | //printf("Decrementing ref-count to %d\n", *pRefCnt ); |
124 | pRefCnt = NULL; | 167 | if( (*pRefCnt) == 0 ) |
125 | pData = NULL; | 168 | { |
169 | delete pRefCnt; | ||
170 | delete pData; | ||
171 | pRefCnt = NULL; | ||
172 | pData = NULL; | ||
173 | } | ||
126 | } | 174 | } |
127 | } | 175 | } |
128 | } | ||
129 | 176 | ||
130 | mutable int32_t *pRefCnt; | 177 | mutable int32_t *pRefCnt; |
131 | mutable T *pData; | 178 | mutable T *pData; |
132 | }; | 179 | }; |
133 | 180 | ||
134 | template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src ) | 181 | template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src ) |
135 | { | 182 | { |
136 | SPtr<Tb> ret; | 183 | SPtr<Tb> ret; |
137 | ret.pRefCnt = src.pRefCnt; | 184 | ret.pRefCnt = src.pRefCnt; |
138 | ret.pData = dynamic_cast<Tb *>(src.pData); | 185 | ret.pData = dynamic_cast<Tb *>(src.pData); |
139 | if( ret.pRefCnt ) | 186 | if( ret.pRefCnt ) |
140 | (*(ret.pRefCnt)) += 1; | 187 | (*(ret.pRefCnt)) += 1; |
141 | return ret; | 188 | return ret; |
189 | } | ||
142 | } | 190 | } |
143 | 191 | ||
144 | #endif | 192 | #endif |
diff --git a/src/stream.cpp b/src/stream.cpp index 856a58d..267a7d1 100644 --- a/src/stream.cpp +++ b/src/stream.cpp | |||
@@ -1,10 +1,10 @@ | |||
1 | #include "stream.h" | 1 | #include "stream.h" |
2 | 2 | ||
3 | Stream::Stream() | 3 | Bu::Stream::Stream() |
4 | { | 4 | { |
5 | } | 5 | } |
6 | 6 | ||
7 | Stream::~Stream() | 7 | Bu::Stream::~Stream() |
8 | { | 8 | { |
9 | } | 9 | } |
10 | 10 | ||
diff --git a/src/stream.h b/src/stream.h index e086e28..1e236a6 100644 --- a/src/stream.h +++ b/src/stream.h | |||
@@ -1,27 +1,143 @@ | |||
1 | #ifndef STREAM_H | 1 | #ifndef BU_STREAM_H |
2 | #define STREAM_H | 2 | #define BU_STREAM_H |
3 | 3 | ||
4 | #include <stdint.h> | 4 | #include <stdint.h> |
5 | #include <stdio.h> | 5 | #include <stdio.h> |
6 | 6 | ||
7 | class Stream | 7 | namespace Bu |
8 | { | 8 | { |
9 | public: | 9 | /** |
10 | Stream(); | 10 | * The basis for a completely general data transport mechanism. Anything |
11 | virtual ~Stream(); | 11 | * that inherits from this should provide at least the basic read and/or |
12 | * write functions, and very probably the close function. Any functions | ||
13 | * that aren't supported should throw an exception if called. | ||
14 | * | ||
15 | * The constructor of a child class should pretty much universally be used | ||
16 | * to open the stream. I can't think of anything that should require an | ||
17 | * exception. | ||
18 | */ | ||
19 | class Stream | ||
20 | { | ||
21 | public: | ||
22 | Stream(); | ||
23 | virtual ~Stream(); | ||
12 | 24 | ||
13 | virtual void close() = 0; | 25 | /** |
14 | virtual size_t read( char *pBuf, size_t nBytes ) = 0; | 26 | * Close the stream. |
15 | virtual size_t write( const char *pBuf, size_t nBytes ) = 0; | 27 | */ |
28 | virtual void close() = 0; | ||
16 | 29 | ||
17 | virtual long tell() = 0; | 30 | /** |
18 | virtual void seek( long offset ) = 0; | 31 | * Read data from the stream into a buffer. |
19 | virtual void setPos( long pos ) = 0; | 32 | *@param pBuf (void *) Buffer which will be filled. |
20 | virtual void setPosEnd( long pos ) = 0; | 33 | *@param nBytes (size_t) Max data to read. |
21 | virtual bool isEOS() = 0; | 34 | *@returns (size_t) Amount of data read. |
35 | */ | ||
36 | virtual size_t read( void *pBuf, size_t nBytes ) = 0; | ||
22 | 37 | ||
23 | private: | 38 | /** |
39 | * Write data to the stream. | ||
40 | *@param pBuf (const void *) The data to be written. | ||
41 | *@param nBytes (size_t) Amount of data to write from pBuf. | ||
42 | *@returns (size_t) Amount of data actually written. | ||
43 | */ | ||
44 | virtual size_t write( const void *pBuf, size_t nBytes ) = 0; | ||
24 | 45 | ||
25 | }; | 46 | /** |
47 | * Get the current position in the stream. | ||
48 | *@returns (long) The current position in the stream. | ||
49 | */ | ||
50 | virtual long tell() = 0; | ||
51 | |||
52 | /** | ||
53 | * Seek to a position in the stream relative to the current position. | ||
54 | *@param offset (long) Offset from current position to seek to. | ||
55 | */ | ||
56 | virtual void seek( long offset ) = 0; | ||
57 | |||
58 | /** | ||
59 | * Set position in the stream relative to the start of the stream. | ||
60 | *@param pos (long) The position. | ||
61 | */ | ||
62 | virtual void setPos( long pos ) = 0; | ||
63 | |||
64 | /** | ||
65 | * Set position in the stream relative to the end of the stream. | ||
66 | *@param pos (long) The position. | ||
67 | */ | ||
68 | virtual void setPosEnd( long pos ) = 0; | ||
69 | |||
70 | /** | ||
71 | * Are we at the end of the stream? | ||
72 | *@returns (bool) Are we at the end of the stream? | ||
73 | */ | ||
74 | virtual bool isEOS() = 0; | ||
75 | |||
76 | /** | ||
77 | * Is the stream open? | ||
78 | *@returns (bool) Is the stream open? | ||
79 | */ | ||
80 | virtual bool isOpen() = 0; | ||
81 | |||
82 | /** | ||
83 | * Flush any data still held in buffers. | ||
84 | */ | ||
85 | virtual void flush() = 0; | ||
86 | |||
87 | /** | ||
88 | * In non-blocking streams this indicates if a read operation will | ||
89 | * return data at the moment or not. In blocking streams this should | ||
90 | * return the same value as isEOS(). | ||
91 | */ | ||
92 | virtual bool canRead() = 0; | ||
93 | |||
94 | /** | ||
95 | * In non-blocking streams this indicates if a write operation will | ||
96 | * succeed or fail. In some cases writing is not allowed (e.g. | ||
97 | * internal buffers are full) temporarilly. In blocking streams this | ||
98 | * should return the same value as isWritable. | ||
99 | */ | ||
100 | virtual bool canWrite() = 0; | ||
101 | |||
102 | /** | ||
103 | * Indicates if the stream is capable of read operations. This does not | ||
104 | * indicate if such operations will return useful data, see canRead for | ||
105 | * that. | ||
106 | */ | ||
107 | virtual bool isReadable() = 0; | ||
108 | |||
109 | /** | ||
110 | * Indicates if the stream is capable of write operations. This does | ||
111 | * not indicate if such operations will succeed or fail, see canWrite | ||
112 | * for that. | ||
113 | */ | ||
114 | virtual bool isWritable() = 0; | ||
115 | |||
116 | /** | ||
117 | * Indicates if the stream is capable of seek operations. This is | ||
118 | * generally false for non-blocking streams. Some buffered streams may | ||
119 | * support limited in-buffer seeking. | ||
120 | */ | ||
121 | virtual bool isSeekable() = 0; | ||
122 | |||
123 | /** | ||
124 | * Are we currently set to block mode? | ||
125 | *@returns (bool) | ||
126 | */ | ||
127 | virtual bool isBlocking() = 0; | ||
128 | |||
129 | /** | ||
130 | * Set stream to blocking or non-blocking mode. | ||
131 | *@param bBlocking (bool) Whether we should block or not. | ||
132 | */ | ||
133 | virtual void setBlocking( bool bBlocking=true ) = 0; | ||
134 | |||
135 | public: // Filters | ||
136 | |||
137 | |||
138 | private: | ||
139 | |||
140 | }; | ||
141 | } | ||
26 | 142 | ||
27 | #endif | 143 | #endif |
diff --git a/src/tafnode.cpp b/src/tafnode.cpp new file mode 100644 index 0000000..53b782e --- /dev/null +++ b/src/tafnode.cpp | |||
@@ -0,0 +1,165 @@ | |||
1 | #include "tafnode.h" | ||
2 | |||
3 | Bu::TafNode::TafNode( NodeType eType ) : | ||
4 | eType( eType ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | Bu::TafNode::~TafNode() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | const Bu::TafNode::NodeType Bu::TafNode::getType() const | ||
13 | { | ||
14 | return eType; | ||
15 | } | ||
16 | |||
17 | /* | ||
18 | const Bu::TafNode::PropList &Bu::TafNode::getProperties( const Bu::FString &sName ) const | ||
19 | { | ||
20 | return hProp.get( sName ); | ||
21 | } | ||
22 | |||
23 | const Bu::TafNode::NodeList &Bu::TafNode::getChildren( const Bu::FString &sName ) const | ||
24 | { | ||
25 | return hChildren.get( sName ); | ||
26 | } | ||
27 | |||
28 | const Bu::FString &Bu::TafNode::getProperty( const Bu::FString &sName ) const | ||
29 | { | ||
30 | return getProperties( sName ).first(); | ||
31 | } | ||
32 | |||
33 | const Bu::TafNode *Bu::TafNode::getChild( const Bu::FString &sName ) const | ||
34 | { | ||
35 | return getChildren( sName ).first(); | ||
36 | } | ||
37 | */ | ||
38 | |||
39 | Bu::TafGroup::TafGroup( const Bu::FString &sName ) : | ||
40 | TafNode( typeGroup ), | ||
41 | sName( sName ) | ||
42 | { | ||
43 | } | ||
44 | |||
45 | Bu::TafGroup::~TafGroup() | ||
46 | { | ||
47 | //printf("Entering Bu::TafNode::~TafNode() \"%s\"\n", sName.getStr() ); | ||
48 | for( NodeList::iterator i = lChildren.begin(); i != lChildren.end(); i++ ) | ||
49 | { | ||
50 | delete (*i); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | const Bu::FString &Bu::TafGroup::getName() const | ||
55 | { | ||
56 | return sName; | ||
57 | } | ||
58 | |||
59 | Bu::TafNode *Bu::TafGroup::addChild( Bu::TafNode *pNode ) | ||
60 | { | ||
61 | switch( pNode->getType() ) | ||
62 | { | ||
63 | case typeGroup: | ||
64 | addChild( (Bu::TafGroup *)pNode ); | ||
65 | break; | ||
66 | |||
67 | case typeProperty: | ||
68 | addChild( (Bu::TafProperty *)pNode ); | ||
69 | break; | ||
70 | |||
71 | case typeComment: | ||
72 | addChild( (Bu::TafComment *)pNode ); | ||
73 | break; | ||
74 | } | ||
75 | |||
76 | return pNode; | ||
77 | } | ||
78 | |||
79 | Bu::TafGroup *Bu::TafGroup::addChild( TafGroup *pNode ) | ||
80 | { | ||
81 | TafGroup *pGroup = (TafGroup *)pNode; | ||
82 | if( !hChildren.has( pGroup->getName() ) ) | ||
83 | hChildren.insert( pGroup->getName(), GroupList() ); | ||
84 | hChildren.get( pGroup->getName() ).append( pGroup ); | ||
85 | lChildren.append( pNode ); | ||
86 | return pNode; | ||
87 | } | ||
88 | |||
89 | Bu::TafProperty *Bu::TafGroup::addChild( TafProperty *pNode ) | ||
90 | { | ||
91 | TafProperty *pProperty = (TafProperty *)pNode; | ||
92 | if( !hProp.has( pProperty->getName() ) ) | ||
93 | hProp.insert( pProperty->getName(), PropList() ); | ||
94 | hProp.get( pProperty->getName() ).append( pProperty->getValue() ); | ||
95 | lChildren.append( pNode ); | ||
96 | return pNode; | ||
97 | } | ||
98 | |||
99 | Bu::TafComment *Bu::TafGroup::addChild( TafComment *pNode ) | ||
100 | { | ||
101 | lChildren.append( pNode ); | ||
102 | return pNode; | ||
103 | } | ||
104 | |||
105 | const Bu::TafGroup::GroupList &Bu::TafGroup::getChildren( const Bu::FString &sName ) const | ||
106 | { | ||
107 | return hChildren.get( sName ); | ||
108 | } | ||
109 | |||
110 | const Bu::TafGroup::NodeList &Bu::TafGroup::getChildren() const | ||
111 | { | ||
112 | return lChildren; | ||
113 | } | ||
114 | |||
115 | const Bu::TafGroup *Bu::TafGroup::getChild( const Bu::FString &sName ) const | ||
116 | { | ||
117 | return hChildren.get( sName ).first(); | ||
118 | } | ||
119 | |||
120 | const Bu::TafGroup::PropList &Bu::TafGroup::getProperties( const Bu::FString &sName ) const | ||
121 | { | ||
122 | return hProp.get( sName ); | ||
123 | } | ||
124 | |||
125 | const Bu::FString &Bu::TafGroup::getProperty( const Bu::FString &sName ) const | ||
126 | { | ||
127 | return hProp.get( sName ).first(); | ||
128 | } | ||
129 | |||
130 | Bu::TafProperty::TafProperty( const Bu::FString &sName, const Bu::FString &sValue ) : | ||
131 | TafNode( typeProperty ), | ||
132 | sName( sName ), | ||
133 | sValue( sValue ) | ||
134 | { | ||
135 | } | ||
136 | |||
137 | Bu::TafProperty::~TafProperty() | ||
138 | { | ||
139 | } | ||
140 | |||
141 | const Bu::FString &Bu::TafProperty::getName() const | ||
142 | { | ||
143 | return sName; | ||
144 | } | ||
145 | |||
146 | const Bu::FString &Bu::TafProperty::getValue() const | ||
147 | { | ||
148 | return sValue; | ||
149 | } | ||
150 | |||
151 | Bu::TafComment::TafComment( const Bu::FString &sText ) : | ||
152 | TafNode( typeComment ), | ||
153 | sText( sText ) | ||
154 | { | ||
155 | } | ||
156 | |||
157 | Bu::TafComment::~TafComment() | ||
158 | { | ||
159 | } | ||
160 | |||
161 | const Bu::FString &Bu::TafComment::getText() const | ||
162 | { | ||
163 | return sText; | ||
164 | } | ||
165 | |||
diff --git a/src/tafnode.h b/src/tafnode.h new file mode 100644 index 0000000..cb4093f --- /dev/null +++ b/src/tafnode.h | |||
@@ -0,0 +1,94 @@ | |||
1 | #ifndef BU_TAF_NODE_H | ||
2 | #define BU_TAF_NODE_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include "bu/fstring.h" | ||
6 | #include "bu/hash.h" | ||
7 | #include "bu/list.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | /** | ||
12 | * | ||
13 | */ | ||
14 | class TafNode | ||
15 | { | ||
16 | public: | ||
17 | enum NodeType | ||
18 | { | ||
19 | typeGroup, | ||
20 | typeProperty, | ||
21 | typeComment | ||
22 | }; | ||
23 | |||
24 | public: | ||
25 | TafNode( NodeType eType ); | ||
26 | virtual ~TafNode(); | ||
27 | |||
28 | const NodeType getType() const; | ||
29 | |||
30 | private: | ||
31 | NodeType eType; | ||
32 | }; | ||
33 | |||
34 | class TafProperty; | ||
35 | class TafComment; | ||
36 | class TafGroup : public TafNode | ||
37 | { | ||
38 | public: | ||
39 | typedef Bu::List<Bu::FString> PropList; | ||
40 | typedef Bu::Hash<Bu::FString, PropList> PropHash; | ||
41 | typedef Bu::List<class Bu::TafGroup *> GroupList; | ||
42 | typedef Bu::Hash<Bu::FString, GroupList> GroupHash; | ||
43 | typedef Bu::List<class Bu::TafNode *> NodeList; | ||
44 | |||
45 | TafGroup( const Bu::FString &sName ); | ||
46 | virtual ~TafGroup(); | ||
47 | |||
48 | const Bu::FString &getName() const; | ||
49 | |||
50 | const Bu::FString &getProperty( const Bu::FString &sName ) const; | ||
51 | const PropList &getProperties( const Bu::FString &sName ) const; | ||
52 | const TafGroup *getChild( const Bu::FString &sName ) const; | ||
53 | const GroupList &getChildren( const Bu::FString &sName ) const; | ||
54 | TafNode *addChild( TafNode *pNode ); | ||
55 | TafGroup *addChild( TafGroup *pNode ); | ||
56 | TafProperty *addChild( TafProperty *pNode ); | ||
57 | TafComment *addChild( TafComment *pNode ); | ||
58 | const NodeList &getChildren() const; | ||
59 | |||
60 | private: | ||
61 | Bu::FString sName; | ||
62 | PropHash hProp; | ||
63 | GroupHash hChildren; | ||
64 | NodeList lChildren; | ||
65 | }; | ||
66 | |||
67 | class TafProperty : public TafNode | ||
68 | { | ||
69 | public: | ||
70 | TafProperty( const Bu::FString &sName, const Bu::FString &sValue ); | ||
71 | virtual ~TafProperty(); | ||
72 | |||
73 | const Bu::FString &getName() const; | ||
74 | const Bu::FString &getValue() const; | ||
75 | |||
76 | private: | ||
77 | Bu::FString sName; | ||
78 | Bu::FString sValue; | ||
79 | }; | ||
80 | |||
81 | class TafComment : public TafNode | ||
82 | { | ||
83 | public: | ||
84 | TafComment( const Bu::FString &sText ); | ||
85 | virtual ~TafComment(); | ||
86 | |||
87 | const Bu::FString &getText() const; | ||
88 | |||
89 | private: | ||
90 | Bu::FString sText; | ||
91 | }; | ||
92 | } | ||
93 | |||
94 | #endif | ||
diff --git a/src/tafreader.cpp b/src/tafreader.cpp new file mode 100644 index 0000000..db465e9 --- /dev/null +++ b/src/tafreader.cpp | |||
@@ -0,0 +1,155 @@ | |||
1 | #include "bu/tafreader.h" | ||
2 | #include "bu/exceptions.h" | ||
3 | #include "bu/fstring.h" | ||
4 | |||
5 | using namespace Bu; | ||
6 | |||
7 | Bu::TafReader::TafReader( Bu::Stream &sIn ) : | ||
8 | c( 0 ), | ||
9 | sIn( sIn ) | ||
10 | { | ||
11 | next(); next(); | ||
12 | } | ||
13 | |||
14 | Bu::TafReader::~TafReader() | ||
15 | { | ||
16 | |||
17 | } | ||
18 | |||
19 | Bu::TafGroup *Bu::TafReader::readGroup() | ||
20 | { | ||
21 | ws(); | ||
22 | if( c != '{' ) | ||
23 | throw TafException("Expected '{'"); | ||
24 | next(); | ||
25 | ws(); | ||
26 | FString sName = readStr(); | ||
27 | TafGroup *pGroup = new TafGroup( sName ); | ||
28 | next(); | ||
29 | //printf("Node[%s]:\n", sName.getStr() ); | ||
30 | |||
31 | groupContent( pGroup ); | ||
32 | |||
33 | if( c != '}' ) | ||
34 | throw TafException("Expected '}'"); | ||
35 | |||
36 | next(); | ||
37 | |||
38 | return pGroup; | ||
39 | } | ||
40 | |||
41 | void Bu::TafReader::groupContent( Bu::TafGroup *pGroup ) | ||
42 | { | ||
43 | for(;;) | ||
44 | { | ||
45 | ws(); | ||
46 | if( c == '{' ) | ||
47 | pGroup->addChild( readGroup() ); | ||
48 | else if( c == '}' ) | ||
49 | return; | ||
50 | else if( c == '/' && la == '*' ) | ||
51 | pGroup->addChild( readComment() ); | ||
52 | else | ||
53 | pGroup->addChild( readProperty() ); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | Bu::TafProperty *Bu::TafReader::readProperty() | ||
58 | { | ||
59 | FString sName = readStr(); | ||
60 | ws(); | ||
61 | if( c != '=' ) | ||
62 | { | ||
63 | //printf(" %s (true)\n", sName.getStr() ); | ||
64 | return new Bu::TafProperty( sName, "" ); | ||
65 | } | ||
66 | next(); | ||
67 | FString sValue = readStr(); | ||
68 | return new Bu::TafProperty( sName, sValue ); | ||
69 | //printf(" %s = %s\n", sName.getStr(), sValue.getStr() ); | ||
70 | } | ||
71 | |||
72 | Bu::TafComment *Bu::TafReader::readComment() | ||
73 | { | ||
74 | next(); | ||
75 | FString sCmnt; | ||
76 | for(;;) | ||
77 | { | ||
78 | next(); | ||
79 | if( c == '*' && la == '/' ) | ||
80 | break; | ||
81 | sCmnt += c; | ||
82 | } | ||
83 | |||
84 | return new TafComment( sCmnt ); | ||
85 | } | ||
86 | |||
87 | Bu::FString Bu::TafReader::readStr() | ||
88 | { | ||
89 | ws(); | ||
90 | FString s; | ||
91 | if( c == '"' ) | ||
92 | { | ||
93 | next(); | ||
94 | for(;;) | ||
95 | { | ||
96 | if( c == '\\' ) | ||
97 | { | ||
98 | next(); | ||
99 | if( c == 'x' ) | ||
100 | { | ||
101 | char code[3]={'\0','\0','\0'}; | ||
102 | next(); | ||
103 | code[0] = c; | ||
104 | next(); | ||
105 | code[1] = c; | ||
106 | c = (unsigned char)strtol( code, NULL, 16 ); | ||
107 | } | ||
108 | else if( c == '"' ) | ||
109 | c = '"'; | ||
110 | else | ||
111 | throw TafException("Invalid escape sequence."); | ||
112 | } | ||
113 | else if( c == '"' ) | ||
114 | break; | ||
115 | s += c; | ||
116 | next(); | ||
117 | } | ||
118 | next(); | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | for(;;) | ||
123 | { | ||
124 | if( isws() || c == '}' || c == '{' || c == ':' || c == '=' ) | ||
125 | break; | ||
126 | s += c; | ||
127 | next(); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | return s; | ||
132 | } | ||
133 | |||
134 | void Bu::TafReader::ws() | ||
135 | { | ||
136 | for(;;) | ||
137 | { | ||
138 | if( !isws() ) | ||
139 | return; | ||
140 | |||
141 | next(); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | bool Bu::TafReader::isws() | ||
146 | { | ||
147 | return (c == ' ' || c == '\t' || c == '\n' || c == '\r'); | ||
148 | } | ||
149 | |||
150 | void Bu::TafReader::next() | ||
151 | { | ||
152 | c = la; | ||
153 | sIn.read( &la, 1 ); | ||
154 | } | ||
155 | |||
diff --git a/src/tafreader.h b/src/tafreader.h new file mode 100644 index 0000000..eeaafb3 --- /dev/null +++ b/src/tafreader.h | |||
@@ -0,0 +1,35 @@ | |||
1 | #ifndef BU_TAF_READER_H | ||
2 | #define BU_TAF_READER_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include "bu/tafnode.h" | ||
6 | #include "bu/stream.h" | ||
7 | #include "bu/fstring.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | /** | ||
12 | * | ||
13 | */ | ||
14 | class TafReader | ||
15 | { | ||
16 | public: | ||
17 | TafReader( Bu::Stream &sIn ); | ||
18 | virtual ~TafReader(); | ||
19 | |||
20 | Bu::TafGroup *readGroup(); | ||
21 | |||
22 | private: | ||
23 | void groupContent( Bu::TafGroup *pNode ); | ||
24 | Bu::TafProperty *readProperty(); | ||
25 | Bu::TafComment *readComment(); | ||
26 | void ws(); | ||
27 | bool isws(); | ||
28 | void next(); | ||
29 | Bu::FString readStr(); | ||
30 | char c, la; | ||
31 | Bu::Stream &sIn; | ||
32 | }; | ||
33 | } | ||
34 | |||
35 | #endif | ||
diff --git a/src/tafwriter.cpp b/src/tafwriter.cpp new file mode 100644 index 0000000..6b505ef --- /dev/null +++ b/src/tafwriter.cpp | |||
@@ -0,0 +1,70 @@ | |||
1 | #include "tafwriter.h" | ||
2 | |||
3 | Bu::TafWriter::TafWriter( Bu::Stream &sOut ) : | ||
4 | sOut( sOut ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | Bu::TafWriter::~TafWriter() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | void Bu::TafWriter::writeGroup( const Bu::TafGroup *pRoot ) | ||
13 | { | ||
14 | sOut.write("{", 1 ); | ||
15 | writeString( pRoot->getName() ); | ||
16 | sOut.write(": ", 2 ); | ||
17 | const Bu::TafGroup::NodeList &nl = pRoot->getChildren(); | ||
18 | for( Bu::TafGroup::NodeList::const_iterator i = nl.begin(); i != nl.end(); i++ ) | ||
19 | { | ||
20 | switch( (*i)->getType() ) | ||
21 | { | ||
22 | case Bu::TafNode::typeGroup: | ||
23 | writeGroup( (Bu::TafGroup *)(*i) ); | ||
24 | break; | ||
25 | |||
26 | case Bu::TafNode::typeProperty: | ||
27 | writeProperty( (Bu::TafProperty *)(*i) ); | ||
28 | break; | ||
29 | |||
30 | case Bu::TafNode::typeComment: | ||
31 | writeComment( (Bu::TafComment *)(*i) ); | ||
32 | break; | ||
33 | } | ||
34 | } | ||
35 | sOut.write("}", 1 ); | ||
36 | } | ||
37 | |||
38 | void Bu::TafWriter::writeProperty( const Bu::TafProperty *pProp ) | ||
39 | { | ||
40 | writeString( pProp->getName() ); | ||
41 | if( pProp->getValue().getStr() != NULL ) | ||
42 | { | ||
43 | sOut.write("=", 1 ); | ||
44 | writeString( pProp->getValue() ); | ||
45 | } | ||
46 | sOut.write(" ", 1 ); | ||
47 | } | ||
48 | |||
49 | void Bu::TafWriter::writeComment( const Bu::TafComment *pComment ) | ||
50 | { | ||
51 | sOut.write("/*", 2 ); | ||
52 | sOut.write( pComment->getText().getStr(), pComment->getText().getSize() ); | ||
53 | sOut.write("*/ ", 3 ); | ||
54 | } | ||
55 | |||
56 | void Bu::TafWriter::writeString( const Bu::FString &str ) | ||
57 | { | ||
58 | if( str.getStr() == NULL ) | ||
59 | return; | ||
60 | sOut.write("\"", 1 ); | ||
61 | for( const char *s = str.getStr(); *s; s++ ) | ||
62 | { | ||
63 | if( *s == '\"' ) | ||
64 | sOut.write("\\\"", 2 ); | ||
65 | else | ||
66 | sOut.write( s, 1 ); | ||
67 | } | ||
68 | sOut.write("\"", 1 ); | ||
69 | } | ||
70 | |||
diff --git a/src/tafwriter.h b/src/tafwriter.h new file mode 100644 index 0000000..5f80504 --- /dev/null +++ b/src/tafwriter.h | |||
@@ -0,0 +1,30 @@ | |||
1 | #ifndef BU_TAF_WRITER_H | ||
2 | #define BU_TAF_WRITER_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include "bu/tafnode.h" | ||
6 | #include "bu/stream.h" | ||
7 | #include "bu/fstring.h" | ||
8 | |||
9 | namespace Bu | ||
10 | { | ||
11 | /** | ||
12 | * | ||
13 | */ | ||
14 | class TafWriter | ||
15 | { | ||
16 | public: | ||
17 | TafWriter( Bu::Stream &sOut ); | ||
18 | virtual ~TafWriter(); | ||
19 | |||
20 | void writeGroup( const Bu::TafGroup *pRoot ); | ||
21 | |||
22 | private: | ||
23 | void writeProperty( const Bu::TafProperty *pProp ); | ||
24 | void writeComment( const Bu::TafComment *pComment ); | ||
25 | void writeString( const Bu::FString &str ); | ||
26 | Bu::Stream &sOut; | ||
27 | }; | ||
28 | } | ||
29 | |||
30 | #endif | ||
diff --git a/src/tests/archive.cpp b/src/tests/archive.cpp new file mode 100644 index 0000000..2035aa6 --- /dev/null +++ b/src/tests/archive.cpp | |||
@@ -0,0 +1,16 @@ | |||
1 | #include "archive.h" | ||
2 | #include "file.h" | ||
3 | |||
4 | using namespace Bu; | ||
5 | |||
6 | int main() | ||
7 | { | ||
8 | File f("test.dat", "wb"); | ||
9 | Archive ar( f, Archive::save ); | ||
10 | |||
11 | std::string s("Hello there"); | ||
12 | ar << s; | ||
13 | |||
14 | return 0; | ||
15 | } | ||
16 | |||
diff --git a/src/tests/atom.cpp b/src/tests/atom.cpp new file mode 100644 index 0000000..2077bfd --- /dev/null +++ b/src/tests/atom.cpp | |||
@@ -0,0 +1,25 @@ | |||
1 | #include "bu/atom.h" | ||
2 | #include <stdio.h> | ||
3 | #include <stdlib.h> | ||
4 | |||
5 | typedef struct bob | ||
6 | { | ||
7 | int a, b; | ||
8 | } bob; | ||
9 | int main() | ||
10 | { | ||
11 | Bu::Atom<int> aInt; | ||
12 | Bu::Atom<char *> aStr; | ||
13 | Bu::Atom<bob> aBob; | ||
14 | |||
15 | aBob = bob(); | ||
16 | aBob->a = 5; | ||
17 | |||
18 | aStr.set("Hey there, dude"); | ||
19 | aInt.set( 55 ); | ||
20 | int me = aInt; | ||
21 | aInt = 12; | ||
22 | printf("%d, %d\n", aInt.get(), me ); | ||
23 | printf("%s\n", aStr.get() ); | ||
24 | } | ||
25 | |||
diff --git a/src/tests/bzip2.cpp b/src/tests/bzip2.cpp new file mode 100644 index 0000000..683d3d7 --- /dev/null +++ b/src/tests/bzip2.cpp | |||
@@ -0,0 +1,23 @@ | |||
1 | #include "bu/bzip2.h" | ||
2 | #include "bu/file.h" | ||
3 | |||
4 | int main( int argc, char *argv[] ) | ||
5 | { | ||
6 | char buf[1024]; | ||
7 | size_t nRead; | ||
8 | |||
9 | Bu::File f( "test.bz2", "wb" ); | ||
10 | Bu::BZip2 bz2( f ); | ||
11 | |||
12 | Bu::File fin( argv[1], "rb"); | ||
13 | |||
14 | for(;;) | ||
15 | { | ||
16 | nRead = fin.read( buf, 1024 ); | ||
17 | if( nRead > 0 ) | ||
18 | bz2.write( buf, nRead ); | ||
19 | if( fin.isEOS() ) | ||
20 | break; | ||
21 | } | ||
22 | } | ||
23 | |||
diff --git a/src/tests/constsptr.cpp b/src/tests/constsptr.cpp deleted file mode 100644 index e6f87c7..0000000 --- a/src/tests/constsptr.cpp +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include "sptr.h" | ||
3 | |||
4 | template <typename T> | ||
5 | class DataBase | ||
6 | { | ||
7 | public: | ||
8 | DataBase(): | ||
9 | _bHas(false) | ||
10 | { | ||
11 | } | ||
12 | |||
13 | virtual ~DataBase() | ||
14 | { | ||
15 | clr(); | ||
16 | } | ||
17 | |||
18 | virtual bool has() const | ||
19 | { | ||
20 | return _bHas; | ||
21 | } | ||
22 | |||
23 | virtual void clr() | ||
24 | { | ||
25 | _bHas = false; | ||
26 | } | ||
27 | |||
28 | virtual void set(T d) | ||
29 | { | ||
30 | _tVal = d; | ||
31 | _bHas = true; | ||
32 | } | ||
33 | |||
34 | virtual T const &get() const | ||
35 | { | ||
36 | if(!has()) | ||
37 | throw "no data"; | ||
38 | return _tVal; | ||
39 | } | ||
40 | |||
41 | virtual T &get() | ||
42 | { | ||
43 | if(!has()) | ||
44 | throw "no data"; | ||
45 | return _tVal; | ||
46 | } | ||
47 | |||
48 | protected: | ||
49 | bool _bHas; | ||
50 | T _tVal; | ||
51 | }; | ||
52 | |||
53 | |||
54 | class Test | ||
55 | { | ||
56 | public: | ||
57 | Test(){}; | ||
58 | virtual ~Test(){}; | ||
59 | |||
60 | void set(int i) | ||
61 | { | ||
62 | _i = i; | ||
63 | } | ||
64 | |||
65 | int get() const | ||
66 | { | ||
67 | return _i; | ||
68 | } | ||
69 | |||
70 | private: | ||
71 | int _i; | ||
72 | }; | ||
73 | |||
74 | int main() | ||
75 | { | ||
76 | typedef SPtr<Test> TestPtr; | ||
77 | |||
78 | TestPtr t1(new Test); | ||
79 | t1->set(42); | ||
80 | |||
81 | printf("t1: %d.\n", t1->get()); | ||
82 | |||
83 | const TestPtr t2 = t1; | ||
84 | |||
85 | printf("t2: %d.\n", t2->get()); | ||
86 | |||
87 | typedef DataBase<const TestPtr> DBTP; | ||
88 | |||
89 | DBTP db; | ||
90 | db.set(t1); | ||
91 | |||
92 | printf("dbt1: %d.\n", db.get()->get()); | ||
93 | } | ||
94 | |||
diff --git a/src/tests/constsptr2.cpp b/src/tests/constsptr2.cpp deleted file mode 100644 index 8ccb20c..0000000 --- a/src/tests/constsptr2.cpp +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | #include "sptr.h" | ||
2 | |||
3 | void nonsptr() | ||
4 | { | ||
5 | int a = 5; | ||
6 | int b = 10; | ||
7 | const int *p = &a; | ||
8 | p = &b; | ||
9 | printf("p = %d\n", (*p) ); | ||
10 | //(*p)++; | ||
11 | } | ||
12 | |||
13 | void sptr() | ||
14 | { | ||
15 | int a = 5; | ||
16 | int b = 10; | ||
17 | const SPtr<int> p = new int(a); | ||
18 | p = new int(b); | ||
19 | printf("p = %d\n", (*p) ); | ||
20 | //(*p)++; | ||
21 | } | ||
22 | |||
23 | int main() | ||
24 | { | ||
25 | printf("Non-sptr:\n"); | ||
26 | nonsptr(); | ||
27 | printf("sptr:\n"); | ||
28 | sptr(); | ||
29 | } | ||
30 | |||
diff --git a/src/tests/fstring.cpp b/src/tests/fstring.cpp index 271738c..48dfc5f 100644 --- a/src/tests/fstring.cpp +++ b/src/tests/fstring.cpp | |||
@@ -1,9 +1,28 @@ | |||
1 | #include "hash.h" | 1 | #include "bu/hash.h" |
2 | #include "fstring.h" | 2 | #include "bu/fstring.h" |
3 | #include <sys/time.h> | ||
4 | #include <string> | ||
3 | 5 | ||
4 | FString genThing() | 6 | #ifndef WIN32 |
7 | inline double getTime() | ||
5 | { | 8 | { |
6 | FString bob; | 9 | struct timeval tv; |
10 | gettimeofday( &tv, NULL ); | ||
11 | return ((double)tv.tv_sec) + ((double)tv.tv_usec/1000000.0); | ||
12 | } | ||
13 | #else | ||
14 | #include "windows.h" | ||
15 | #include "winbase.h" | ||
16 | inline double getTime() | ||
17 | { | ||
18 | uint32_t t = (uint32_t) GetTickCount(); | ||
19 | return (double) t / 1000.0; | ||
20 | } | ||
21 | #endif | ||
22 | |||
23 | Bu::FString genThing() | ||
24 | { | ||
25 | Bu::FString bob; | ||
7 | bob.append("ab "); | 26 | bob.append("ab "); |
8 | bob += "cd "; | 27 | bob += "cd "; |
9 | bob += "efg"; | 28 | bob += "efg"; |
@@ -12,20 +31,91 @@ FString genThing() | |||
12 | return bob; | 31 | return bob; |
13 | } | 32 | } |
14 | 33 | ||
15 | void thing( FString str ) | 34 | void thing( Bu::FString str ) |
16 | { | 35 | { |
17 | printf("Hey: %s\n", str.c_str() ); | 36 | printf("Hey: %s\n", str.c_str() ); |
18 | } | 37 | } |
19 | 38 | ||
39 | void copyfunc( std::string temp ) | ||
40 | { | ||
41 | temp += "Hi"; | ||
42 | } | ||
43 | |||
44 | void copyfunc( Bu::FString temp ) | ||
45 | { | ||
46 | temp += "Hi"; | ||
47 | } | ||
48 | |||
49 | void doTimings() | ||
50 | { | ||
51 | Bu::FString fs1, fs2; | ||
52 | std::string ss1, ss2; | ||
53 | double dStart, dEnd, tfs1, tfs2, tfs3, tss1, tss2, tss3; | ||
54 | int nChars = 500000, nChunks=5000, nCopies=5000000, nChunkSize=1024*4; | ||
55 | char *buf = new char[nChunkSize]; | ||
56 | memset( buf, '!', nChunkSize ); | ||
57 | |||
58 | printf("Timing Bu::FString single chars...\n"); | ||
59 | dStart = getTime(); | ||
60 | for( int j = 0; j < nChars; j++ ) fs1 += (char)('a'+(j%26)); | ||
61 | fs1.getStr(); | ||
62 | dEnd = getTime(); | ||
63 | tfs1 = dEnd-dStart; | ||
64 | |||
65 | printf("Timing std::string single chars...\n"); | ||
66 | dStart = getTime(); | ||
67 | for( int j = 0; j < nChars; j++ ) ss1 += (char)('a'+(j%26)); | ||
68 | ss1.c_str(); | ||
69 | dEnd = getTime(); | ||
70 | tss1 = dEnd-dStart; | ||
71 | |||
72 | printf("Timing Bu::FString %d char chunks...\n", nChunkSize); | ||
73 | dStart = getTime(); | ||
74 | for( int j = 0; j < nChunks; j++ ) fs2.append(buf, nChunkSize); | ||
75 | fs2.getStr(); | ||
76 | dEnd = getTime(); | ||
77 | tfs2 = dEnd-dStart; | ||
78 | |||
79 | printf("Timing std::string %d char chunks...\n", nChunkSize); | ||
80 | dStart = getTime(); | ||
81 | for( int j = 0; j < nChunks; j++ ) ss2.append(buf, nChunkSize); | ||
82 | ss2.c_str(); | ||
83 | dEnd = getTime(); | ||
84 | tss2 = dEnd-dStart; | ||
85 | |||
86 | fs2 = "Hello there."; | ||
87 | ss2 = "Hello there."; | ||
88 | printf("Timing Bu::FString copies...\n"); | ||
89 | dStart = getTime(); | ||
90 | for( int j = 0; j < nCopies; j++ ) Bu::FString stmp = fs2; | ||
91 | dEnd = getTime(); | ||
92 | tfs3 = dEnd-dStart; | ||
93 | |||
94 | printf("Timing std::string copies...\n"); | ||
95 | dStart = getTime(); | ||
96 | for( int j = 0; j < nCopies; j++ ) std::string stpm = ss2; | ||
97 | dEnd = getTime(); | ||
98 | tss3 = dEnd-dStart; | ||
99 | |||
100 | printf( | ||
101 | "Results: singles: chunks: copies:\n" | ||
102 | "Bu::FString %10.2f/s %10.2f/s %10.2f/s\n" | ||
103 | "std::string %10.2f/s %10.2f/s %10.2f/s\n", | ||
104 | nChars/tfs1, nChunks/tfs2, nCopies/tfs3, | ||
105 | nChars/tss1, nChunks/tss2, nCopies/tss3 ); | ||
106 | |||
107 | delete[] buf; | ||
108 | } | ||
109 | |||
20 | #define pem printf("---------\n%08X: %s\n%08X: %s\n", (unsigned int)str.c_str(), str.c_str(), (unsigned int)str2.c_str(), str2.c_str() ); | 110 | #define pem printf("---------\n%08X: %s\n%08X: %s\n", (unsigned int)str.c_str(), str.c_str(), (unsigned int)str2.c_str(), str2.c_str() ); |
21 | int main( int argc, char *argv ) | 111 | int main( int argc, char *argv ) |
22 | { | 112 | { |
23 | FString str("th"); | 113 | Bu::FString str("th"); |
24 | 114 | ||
25 | str.prepend("Hello "); | 115 | str.prepend("Hello "); |
26 | str.append("ere."); | 116 | str.append("ere."); |
27 | 117 | ||
28 | FString str2( str ); | 118 | Bu::FString str2( str ); |
29 | pem; | 119 | pem; |
30 | str += " What's up?"; | 120 | str += " What's up?"; |
31 | pem; | 121 | pem; |
@@ -43,6 +133,8 @@ int main( int argc, char *argv ) | |||
43 | thing( str2 ); | 133 | thing( str2 ); |
44 | thing("test."); | 134 | thing("test."); |
45 | 135 | ||
46 | printf("%d == %d\n", __calcHashCode( str ), __calcHashCode( str.c_str() ) ); | 136 | printf("%d == %d\n", Bu::__calcHashCode( str ), Bu::__calcHashCode( str.c_str() ) ); |
137 | |||
138 | doTimings(); | ||
47 | } | 139 | } |
48 | 140 | ||
diff --git a/src/tests/hash.cpp b/src/tests/hash.cpp index 2fc6968..73cfb27 100644 --- a/src/tests/hash.cpp +++ b/src/tests/hash.cpp | |||
@@ -1,116 +1,24 @@ | |||
1 | #include "hash.h" | 1 | #include "bu/hash.h" |
2 | #include "staticstring.h" | 2 | #include "bu/sptr.h" |
3 | 3 | ||
4 | int main() | 4 | typedef struct Bob |
5 | { | 5 | { |
6 | const char *names[]={ | 6 | int nID; |
7 | "Homer the Great", | 7 | } Bob; |
8 | "And Maggie Makes Three", | ||
9 | "Bart's Comet", | ||
10 | "Homie The Clown", | ||
11 | "Bart Vs Australia", | ||
12 | "Homer vs Patty and Selma", | ||
13 | "A star is burns", | ||
14 | "Lisa's Wedding", | ||
15 | "Two Dozen and One Greyhounds", | ||
16 | "The PTA Disbands", | ||
17 | "Round Springfield", | ||
18 | "The Springfield connection", | ||
19 | "Lemon of Troy", | ||
20 | "Who Shot Mr. Burns (Pt. 1)", | ||
21 | "Who Shot Mr. Burns (pt. 2)", | ||
22 | "Radioactive Man", | ||
23 | "Home Sweet Homediddly-dum-doodly", | ||
24 | "Bart Sells His Soul", | ||
25 | "Lisa the Vegetarian", | ||
26 | "Treehouse of horror VI", | ||
27 | "King Size Homer", | ||
28 | "Mother Simpson", | ||
29 | "Sideshow Bob's Last Gleaming", | ||
30 | "The Simpson's 138th Show Spectacular", | ||
31 | "Marge Be Not Proud", | ||
32 | "Team Homer", | ||
33 | "Two Bad Neighbors", | ||
34 | "Scenes From the Class Struggle in Springfield", | ||
35 | "Bart the Fink", | ||
36 | "Lisa the Iconoclast", | ||
37 | "Homer the Smithers", | ||
38 | "The Day the Violence Died", | ||
39 | "A Fish Called Selma", | ||
40 | "Bart on the road", | ||
41 | "22 Short Films about Springfield", | ||
42 | "The Curse of the Flying Hellfish", | ||
43 | "Much Apu about Nothing", | ||
44 | "Homerpalooza", | ||
45 | "The Summer of 4 Ft 2", | ||
46 | "Treehouse of Horror VII", | ||
47 | "You Only Move Twice", | ||
48 | "The Homer They Fall", | ||
49 | "Burns Baby Burns", | ||
50 | "Bart After Dark", | ||
51 | "A Millhouse Divided", | ||
52 | "Lisas Date With Destiny", | ||
53 | "Hurricane Neddy", | ||
54 | "The Mysterious Voyage of Our Homer", | ||
55 | "The Springfield Files", | ||
56 | "The Twisted World of Marge Simpson", | ||
57 | "Mountain of Madness", | ||
58 | NULL | ||
59 | }; | ||
60 | |||
61 | Hash<const char *, int> sTest; | ||
62 | |||
63 | printf("Inserting\n-------------------\n\n"); | ||
64 | for( int j = 0; j < 33; j++ ) | ||
65 | { | ||
66 | sTest[names[j]] = j; | ||
67 | } | ||
68 | |||
69 | printf("Test1: %d, Test2: %d\n", sTest.has("Lemon of Troy"), sTest.has(std::string("Lemon of Troy").c_str() ) ); | ||
70 | |||
71 | sTest.has(std::string("Lemon of Troy").c_str() ); | ||
72 | |||
73 | printf("Getting\n-------------------\n\n"); | ||
74 | |||
75 | sTest.erase("Homer the Great"); | ||
76 | sTest["Bart's Comet"].erase(); | ||
77 | 8 | ||
78 | for( Hash<const char *, int>::iterator i = sTest.begin(); | 9 | int main() |
79 | i != sTest.end(); i++ ) | 10 | { |
80 | { | 11 | Bu::Hash<int, Bu::SPtr<const Bob> > lb; |
81 | Hash<const char *, int>::iterator j = i; | 12 | for( int j = 0; j < 10; j++ ) |
82 | printf("%d: %s\n", (*j).second, (*j).first ); | ||
83 | } | ||
84 | |||
85 | printf("Testing\n-------------------\n\n"); | ||
86 | for( int j = 0; j < 33; j++ ) | ||
87 | { | 13 | { |
88 | if( sTest.has(names[j]) ) | 14 | Bob *b = new Bob; |
89 | { | 15 | b->nID = j; |
90 | if( sTest[names[j]] != j ) | 16 | lb.insert( j, b ); |
91 | { | ||
92 | printf("'%s' should be %d, is %d\n", | ||
93 | names[j], j, | ||
94 | sTest[names[j]].value() | ||
95 | ); | ||
96 | } | ||
97 | } | ||
98 | else | ||
99 | { | ||
100 | printf("Missing element %d, '%s'\n", j, names[j] ); | ||
101 | } | ||
102 | } | 17 | } |
103 | 18 | ||
104 | printf("Clearing\n-------------------\n\n"); | 19 | for( int j = 0; j < 10; j++ ) |
105 | |||
106 | sTest.clear(); | ||
107 | |||
108 | for( Hash<const char *, int>::iterator i = sTest.begin(); | ||
109 | i != sTest.end(); i++ ) | ||
110 | { | 20 | { |
111 | Hash<const char *, int>::iterator j = i; | 21 | printf("%d\n", lb[j].value()->nID ); |
112 | printf("%d: %s\n", (*j).second, (*j).first ); | ||
113 | } | 22 | } |
114 | |||
115 | } | 23 | } |
116 | 24 | ||
diff --git a/src/tests/itoqueue1.cpp b/src/tests/itoqueue1.cpp new file mode 100644 index 0000000..f73f4d3 --- /dev/null +++ b/src/tests/itoqueue1.cpp | |||
@@ -0,0 +1,110 @@ | |||
1 | #include <string> | ||
2 | #include "bu/ito.h" | ||
3 | #include "bu/itoqueue.h" | ||
4 | |||
5 | class Reader : public Bu::Ito | ||
6 | { | ||
7 | public: | ||
8 | Reader( Bu::ItoQueue<std::string *> &q, int id ) : | ||
9 | q( q ), | ||
10 | id( id ) | ||
11 | { | ||
12 | } | ||
13 | |||
14 | void *run() | ||
15 | { | ||
16 | for( int i = 0; i < 10; i++ ) | ||
17 | { | ||
18 | std::string *pStr = q.dequeue( true ); | ||
19 | if( pStr == NULL ) | ||
20 | { | ||
21 | printf("Null received...\n"); | ||
22 | } | ||
23 | else | ||
24 | { | ||
25 | printf("[%d] read: %s\n", id, pStr->c_str() ); | ||
26 | delete pStr; | ||
27 | } | ||
28 | usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) ); | ||
29 | } | ||
30 | |||
31 | return NULL; | ||
32 | } | ||
33 | |||
34 | private: | ||
35 | Bu::ItoQueue<std::string *> &q; | ||
36 | int id; | ||
37 | }; | ||
38 | |||
39 | class Writer : public Bu::Ito | ||
40 | { | ||
41 | public: | ||
42 | Writer( Bu::ItoQueue<std::string *> &q, int id, const char *strbase ) : | ||
43 | q( q ), | ||
44 | strbase( strbase ), | ||
45 | id( id ) | ||
46 | { | ||
47 | } | ||
48 | |||
49 | void *run() | ||
50 | { | ||
51 | for( int i = 0; i < 11; i++ ) | ||
52 | { | ||
53 | usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) ); | ||
54 | q.enqueue( new std::string( strbase ) ); | ||
55 | printf("[%d] write: %s\n", id, strbase ); | ||
56 | } | ||
57 | |||
58 | return NULL; | ||
59 | } | ||
60 | |||
61 | private: | ||
62 | Bu::ItoQueue<std::string *> &q; | ||
63 | const char *strbase; | ||
64 | int id; | ||
65 | }; | ||
66 | |||
67 | int main() | ||
68 | { | ||
69 | Writer *wr[5]; | ||
70 | Reader *rd[5]; | ||
71 | const char bob[][7]={ | ||
72 | {"Test 1"}, | ||
73 | {"Test 2"}, | ||
74 | {"Test 3"}, | ||
75 | {"Test 4"}, | ||
76 | {"Test 5"} | ||
77 | }; | ||
78 | |||
79 | Bu::ItoQueue<std::string *> q; | ||
80 | |||
81 | for( int j = 0; j < 5; j++ ) | ||
82 | { | ||
83 | wr[j] = new Writer( q, j, bob[j] ); | ||
84 | rd[j] = new Reader( q, j ); | ||
85 | } | ||
86 | |||
87 | for( int j = 0; j < 5; j++ ) | ||
88 | { | ||
89 | rd[j]->start(); | ||
90 | } | ||
91 | |||
92 | for( int j = 0; j < 5; j++ ) | ||
93 | { | ||
94 | wr[j]->start(); | ||
95 | } | ||
96 | |||
97 | for( int j = 0; j < 5; j++ ) | ||
98 | { | ||
99 | rd[j]->join(); | ||
100 | } | ||
101 | |||
102 | for( int j = 0; j < 5; j++ ) | ||
103 | { | ||
104 | delete wr[j]; | ||
105 | delete rd[j]; | ||
106 | } | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
diff --git a/src/tests/itoqueue2.cpp b/src/tests/itoqueue2.cpp new file mode 100644 index 0000000..f4b5e19 --- /dev/null +++ b/src/tests/itoqueue2.cpp | |||
@@ -0,0 +1,83 @@ | |||
1 | #include <string> | ||
2 | #include "bu/ito.h" | ||
3 | #include "bu/itoqueue.h" | ||
4 | #include <errno.h> | ||
5 | |||
6 | class Reader : public Bu::Ito | ||
7 | { | ||
8 | public: | ||
9 | Reader( Bu::ItoQueue<std::string *> &q, int id ) : | ||
10 | q( q ), | ||
11 | id( id ) | ||
12 | { | ||
13 | } | ||
14 | |||
15 | void *run() | ||
16 | { | ||
17 | for( int i = 0; i < 10; i++ ) | ||
18 | { | ||
19 | std::string *pStr = q.dequeue( 0, 500000 ); | ||
20 | if( pStr == NULL ) | ||
21 | { | ||
22 | printf("Null received...\n"); | ||
23 | i--; | ||
24 | } | ||
25 | else | ||
26 | { | ||
27 | printf("[%d] read: %s\n", id, pStr->c_str() ); | ||
28 | delete pStr; | ||
29 | } | ||
30 | } | ||
31 | |||
32 | return NULL; | ||
33 | } | ||
34 | |||
35 | private: | ||
36 | Bu::ItoQueue<std::string *> &q; | ||
37 | int id; | ||
38 | }; | ||
39 | |||
40 | class Writer : public Bu::Ito | ||
41 | { | ||
42 | public: | ||
43 | Writer( Bu::ItoQueue<std::string *> &q, int id, const char *strbase ) : | ||
44 | q( q ), | ||
45 | strbase( strbase ), | ||
46 | id( id ) | ||
47 | { | ||
48 | } | ||
49 | |||
50 | void *run() | ||
51 | { | ||
52 | for( int i = 0; i < 11; i++ ) | ||
53 | { | ||
54 | sleep( 2 ); | ||
55 | printf("[%d] write: %s\n", id, strbase ); | ||
56 | q.enqueue( new std::string( strbase ) ); | ||
57 | } | ||
58 | |||
59 | return NULL; | ||
60 | } | ||
61 | |||
62 | private: | ||
63 | Bu::ItoQueue<std::string *> &q; | ||
64 | const char *strbase; | ||
65 | int id; | ||
66 | }; | ||
67 | |||
68 | int main() | ||
69 | { | ||
70 | printf("ETIMEDOUT: %d\n", ETIMEDOUT ); | ||
71 | Bu::ItoQueue<std::string *> q; | ||
72 | Writer wr( q, 0, "writer" ); | ||
73 | Reader rd( q, 0 ); | ||
74 | |||
75 | rd.start(); | ||
76 | wr.start(); | ||
77 | |||
78 | rd.join(); | ||
79 | wr.join(); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
diff --git a/src/tests/list.cpp b/src/tests/list.cpp new file mode 100644 index 0000000..12807a5 --- /dev/null +++ b/src/tests/list.cpp | |||
@@ -0,0 +1,53 @@ | |||
1 | #include "bu/list.h" | ||
2 | #include <list> | ||
3 | |||
4 | typedef struct Bob | ||
5 | { | ||
6 | int nID; | ||
7 | } Bob; | ||
8 | |||
9 | int main() | ||
10 | { | ||
11 | Bu::List<int> l; | ||
12 | |||
13 | l.append( 0 ); | ||
14 | |||
15 | for( int j = 3; j <= 21; j += 3 ) | ||
16 | { | ||
17 | l.append( j ); | ||
18 | l.prepend( -j ); | ||
19 | } | ||
20 | |||
21 | for( Bu::List<int>::iterator i = l.begin(); i != l.end(); i++ ) | ||
22 | { | ||
23 | printf("%d ", *i ); | ||
24 | } | ||
25 | printf("\n"); | ||
26 | for( Bu::List<int>::iterator i = l.begin(); i != l.end(); i++ ) | ||
27 | { | ||
28 | l.erase( i ); | ||
29 | if( i != l.end() ) | ||
30 | printf("%d ", *i ); | ||
31 | } | ||
32 | |||
33 | printf("\n\n"); | ||
34 | |||
35 | Bu::List<Bob> lb; | ||
36 | for( int j = 0; j < 10; j++ ) | ||
37 | { | ||
38 | Bob b; | ||
39 | b.nID = j; | ||
40 | lb.append( b ); | ||
41 | } | ||
42 | |||
43 | const Bu::List<Bob> rb = lb; | ||
44 | |||
45 | for( Bu::List<Bob>::const_iterator i = rb.begin(); i != rb.end(); i++ ) | ||
46 | { | ||
47 | //i->nID += 2; | ||
48 | //(*i).nID = 4; | ||
49 | printf("%d ", i->nID ); | ||
50 | } | ||
51 | printf("\n\n"); | ||
52 | } | ||
53 | |||
diff --git a/src/tests/logger.cpp b/src/tests/logger.cpp new file mode 100644 index 0000000..290f479 --- /dev/null +++ b/src/tests/logger.cpp | |||
@@ -0,0 +1,28 @@ | |||
1 | #include "bu/logger.h" | ||
2 | #include <errno.h> | ||
3 | #include <stdlib.h> | ||
4 | |||
5 | class Thing | ||
6 | { | ||
7 | public: | ||
8 | Thing() | ||
9 | { | ||
10 | lineLog( 2, "Want a thing?"); | ||
11 | } | ||
12 | |||
13 | void go( int i ) | ||
14 | { | ||
15 | lineLog( 1, "GO!!!!"); | ||
16 | } | ||
17 | }; | ||
18 | |||
19 | int main() | ||
20 | { | ||
21 | setLogLevel( 4 ); | ||
22 | setLogFormat("%L: %y-%02m-%02d %h:%02M:%02s %f:%l:%F: %t"); | ||
23 | lineLog( 5, "Hey, error: %s", strerror( errno ) ); | ||
24 | |||
25 | Thing gh; | ||
26 | gh.go( 6); | ||
27 | } | ||
28 | |||
diff --git a/src/tests/ringbuffer.cpp b/src/tests/ringbuffer.cpp new file mode 100644 index 0000000..259ec1f --- /dev/null +++ b/src/tests/ringbuffer.cpp | |||
@@ -0,0 +1,29 @@ | |||
1 | #include "bu/ringbuffer.h" | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | int main() | ||
5 | { | ||
6 | Bu::RingBuffer<uint32_t> ibuf( 10 ); | ||
7 | |||
8 | for( int k = 0; k < 2; k++ ) | ||
9 | { | ||
10 | int j = 1; | ||
11 | for(; j < 7; j++ ) | ||
12 | { | ||
13 | ibuf.enqueue( j ); | ||
14 | } | ||
15 | |||
16 | for(; j < 20; j++ ) | ||
17 | { | ||
18 | ibuf.enqueue( j ); | ||
19 | printf("- %d\n", ibuf.dequeue() ); | ||
20 | } | ||
21 | |||
22 | for(;;) | ||
23 | { | ||
24 | if( ibuf.isEmpty() ) break; | ||
25 | printf(". %d\n", ibuf.dequeue() ); | ||
26 | } | ||
27 | } | ||
28 | } | ||
29 | |||
diff --git a/src/tests/taf.cpp b/src/tests/taf.cpp new file mode 100644 index 0000000..e3da120 --- /dev/null +++ b/src/tests/taf.cpp | |||
@@ -0,0 +1,24 @@ | |||
1 | #include "bu/tafreader.h" | ||
2 | #include "bu/tafwriter.h" | ||
3 | #include "bu/file.h" | ||
4 | |||
5 | int main() | ||
6 | { | ||
7 | Bu::File f("test.taf", "rb"); | ||
8 | Bu::TafReader tr( f ); | ||
9 | |||
10 | Bu::TafGroup *pGroup = tr.readGroup(); | ||
11 | |||
12 | const Bu::TafGroup *pStats = pGroup->getChild("stats"); | ||
13 | printf("%s\n", pStats->getName().getStr() ); | ||
14 | printf(" str = %s\n", pStats->getProperty("str").getStr() ); | ||
15 | |||
16 | { | ||
17 | Bu::File fo("out.taf", "wb"); | ||
18 | Bu::TafWriter tw( fo ); | ||
19 | tw.writeGroup( pGroup ); | ||
20 | } | ||
21 | |||
22 | delete pGroup; | ||
23 | } | ||
24 | |||
diff --git a/src/unit/entities/unit b/src/unit/entities/unit new file mode 100644 index 0000000..28db45f --- /dev/null +++ b/src/unit/entities/unit | |||
@@ -0,0 +1,30 @@ | |||
1 | <?xml version="1.1" ?> | ||
2 | <entity desc="Unit test framework"> | ||
3 | <param name="name" required="yes" desc="Name of the class"/> | ||
4 | <file | ||
5 | name="source" | ||
6 | filename="{=name:%tolower}.cpp" | ||
7 | >#include "bu/unitsuite.h" | ||
8 | |||
9 | class Unit : public Bu::UnitSuite | ||
10 | { | ||
11 | public: | ||
12 | Unit() | ||
13 | { | ||
14 | setName("{=name}"); | ||
15 | addTest( Unit::test01 ); | ||
16 | } | ||
17 | |||
18 | virtual ~Unit() | ||
19 | { | ||
20 | } | ||
21 | |||
22 | void test01() | ||
23 | { | ||
24 | unitTest( 0 == 5 ); | ||
25 | } | ||
26 | }; | ||
27 | |||
28 | int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); } | ||
29 | </file> | ||
30 | </entity> | ||
diff --git a/src/unit/file.cpp b/src/unit/file.cpp new file mode 100644 index 0000000..1eaaf36 --- /dev/null +++ b/src/unit/file.cpp | |||
@@ -0,0 +1,111 @@ | |||
1 | #include "unitsuite.h" | ||
2 | #include "file.h" | ||
3 | #include "exceptions.h" | ||
4 | |||
5 | #include <sys/types.h> | ||
6 | #include <sys/stat.h> | ||
7 | #include <unistd.h> | ||
8 | |||
9 | class Unit : public Bu::UnitSuite | ||
10 | { | ||
11 | public: | ||
12 | Unit() | ||
13 | { | ||
14 | setName("File"); | ||
15 | addTest( Unit::writeFull ); | ||
16 | addTest( Unit::readBlocks ); | ||
17 | addTest( Unit::readError1 ); | ||
18 | addTest( Unit::readError2 ); | ||
19 | } | ||
20 | |||
21 | virtual ~Unit() { } | ||
22 | |||
23 | // | ||
24 | // Tests go here | ||
25 | // | ||
26 | void writeFull() | ||
27 | { | ||
28 | Bu::File sf("testfile1", "wb"); | ||
29 | for( int c = 0; c < 256; c++ ) | ||
30 | { | ||
31 | unsigned char ch = (unsigned char)c; | ||
32 | sf.write( &ch, 1 ); | ||
33 | unitTest( sf.tell() == c+1 ); | ||
34 | } | ||
35 | //unitTest( sf.canRead() == false ); | ||
36 | //unitTest( sf.canWrite() == true ); | ||
37 | //unitTest( sf.canSeek() == true ); | ||
38 | sf.close(); | ||
39 | struct stat sdat; | ||
40 | stat("testfile1", &sdat ); | ||
41 | unitTest( sdat.st_size == 256 ); | ||
42 | } | ||
43 | |||
44 | void readBlocks() | ||
45 | { | ||
46 | Bu::File sf("testfile1", "rb"); | ||
47 | unsigned char buf[50]; | ||
48 | size_t total = 0; | ||
49 | for(;;) | ||
50 | { | ||
51 | size_t s = sf.read( buf, 50 ); | ||
52 | for( size_t c = 0; c < s; c++ ) | ||
53 | { | ||
54 | unitTest( buf[c] == (unsigned char)(c+total) ); | ||
55 | } | ||
56 | total += s; | ||
57 | if( s < 50 ) | ||
58 | { | ||
59 | unitTest( total == 256 ); | ||
60 | unitTest( sf.isEOS() == true ); | ||
61 | break; | ||
62 | } | ||
63 | } | ||
64 | sf.close(); | ||
65 | } | ||
66 | |||
67 | void readError1() | ||
68 | { | ||
69 | try | ||
70 | { | ||
71 | Bu::File sf("doesn'texist", "rb"); | ||
72 | unitFailed("No exception thrown"); | ||
73 | } | ||
74 | catch( Bu::FileException &e ) | ||
75 | { | ||
76 | return; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | void readError2() | ||
81 | { | ||
82 | Bu::File sf("testfile1", "rb"); | ||
83 | char buf[256]; | ||
84 | int r = sf.read( buf, 256 ); | ||
85 | unitTest( r == 256 ); | ||
86 | // You have to read past the end to set the EOS flag. | ||
87 | unitTest( sf.isEOS() == false ); | ||
88 | try | ||
89 | { | ||
90 | if( sf.read( buf, 5 ) > 0 ) | ||
91 | { | ||
92 | unitFailed("Non-zero read result"); | ||
93 | } | ||
94 | else | ||
95 | { | ||
96 | sf.close(); | ||
97 | } | ||
98 | } | ||
99 | catch( Bu::FileException &e ) | ||
100 | { | ||
101 | sf.close(); | ||
102 | return; | ||
103 | } | ||
104 | } | ||
105 | }; | ||
106 | |||
107 | int main( int argc, char *argv[] ) | ||
108 | { | ||
109 | return Unit().run( argc, argv ); | ||
110 | } | ||
111 | |||
diff --git a/src/unit/fstring.cpp b/src/unit/fstring.cpp new file mode 100644 index 0000000..72755eb --- /dev/null +++ b/src/unit/fstring.cpp | |||
@@ -0,0 +1,28 @@ | |||
1 | #include "fstring.h" | ||
2 | #include "unitsuite.h" | ||
3 | |||
4 | class Unit : public Bu::UnitSuite | ||
5 | { | ||
6 | public: | ||
7 | Unit() | ||
8 | { | ||
9 | setName("FString"); | ||
10 | addTest( Unit::test1 ); | ||
11 | } | ||
12 | |||
13 | virtual ~Unit() | ||
14 | { | ||
15 | } | ||
16 | |||
17 | void test1() | ||
18 | { | ||
19 | unitTest( 1 == 1 ); | ||
20 | unitTest( 1 == 0 ); | ||
21 | } | ||
22 | }; | ||
23 | |||
24 | int main( int argc, char *argv[] ) | ||
25 | { | ||
26 | return Unit().run( argc, argv ); | ||
27 | } | ||
28 | |||
diff --git a/src/unit/hash.cpp b/src/unit/hash.cpp new file mode 100644 index 0000000..9ea933f --- /dev/null +++ b/src/unit/hash.cpp | |||
@@ -0,0 +1,40 @@ | |||
1 | #include "bu/fstring.h" | ||
2 | #include "bu/hash.h" | ||
3 | #include "bu/unitsuite.h" | ||
4 | |||
5 | #include <stdio.h> | ||
6 | |||
7 | class Unit : public Bu::UnitSuite | ||
8 | { | ||
9 | private: | ||
10 | typedef Bu::Hash<Bu::FString, int> StrIntHash; | ||
11 | public: | ||
12 | Unit() | ||
13 | { | ||
14 | setName("Hash"); | ||
15 | addTest( Unit::test_probe ); | ||
16 | } | ||
17 | |||
18 | virtual ~Unit() | ||
19 | { | ||
20 | } | ||
21 | |||
22 | void test_probe() | ||
23 | { | ||
24 | StrIntHash h; | ||
25 | char buf[20]; | ||
26 | for(int i=1;i<10000;i++) | ||
27 | { | ||
28 | sprintf(buf,"%d",i); | ||
29 | Bu::FString sTmp(buf); | ||
30 | h[sTmp] = i; | ||
31 | unitTest( h.has(sTmp) ); | ||
32 | } | ||
33 | } | ||
34 | }; | ||
35 | |||
36 | int main( int argc, char *argv[] ) | ||
37 | { | ||
38 | return Unit().run( argc, argv ); | ||
39 | } | ||
40 | |||
diff --git a/src/unit/membuf.cpp b/src/unit/membuf.cpp new file mode 100644 index 0000000..65ba82a --- /dev/null +++ b/src/unit/membuf.cpp | |||
@@ -0,0 +1,37 @@ | |||
1 | #include "bu/unitsuite.h" | ||
2 | #include "bu/membuf.h" | ||
3 | |||
4 | class Unit : public Bu::UnitSuite | ||
5 | { | ||
6 | public: | ||
7 | Unit() | ||
8 | { | ||
9 | setName("MemBuf"); | ||
10 | addTest( Unit::testWriteRead01 ); | ||
11 | } | ||
12 | |||
13 | virtual ~Unit() | ||
14 | { | ||
15 | } | ||
16 | |||
17 | void testWriteRead01() | ||
18 | { | ||
19 | Bu::MemBuf mb; | ||
20 | unitTest( mb.write("ab", 2 ) == 2 ); | ||
21 | unitTest( mb.write("cde", 3 ) == 3 ); | ||
22 | unitTest( mb.write("FG", 2 ) == 2 ); | ||
23 | |||
24 | mb.setPos( 0 ); | ||
25 | |||
26 | char buf[8]; | ||
27 | buf[7] = '\0'; | ||
28 | unitTest( mb.read( buf, 7 ) == 7 ); | ||
29 | unitTest( !strncmp( buf, "abcdeFG", 7 ) ); | ||
30 | unitTest( mb.read( buf, 7 ) == 0 ); | ||
31 | mb.seek( -3 ); | ||
32 | unitTest( mb.read( buf, 7 ) == 3 ); | ||
33 | unitTest( !strncmp( buf, "eFG", 3 ) ); | ||
34 | } | ||
35 | }; | ||
36 | |||
37 | int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); } | ||
diff --git a/src/unit/taf.cpp b/src/unit/taf.cpp new file mode 100644 index 0000000..5e0e914 --- /dev/null +++ b/src/unit/taf.cpp | |||
@@ -0,0 +1,48 @@ | |||
1 | #include "unitsuite.h" | ||
2 | #include "file.h" | ||
3 | #include "tafreader.h" | ||
4 | |||
5 | #include <string.h> | ||
6 | #include <unistd.h> | ||
7 | |||
8 | class Unit : public Bu::UnitSuite | ||
9 | { | ||
10 | public: | ||
11 | Unit() | ||
12 | { | ||
13 | setName("taf"); | ||
14 | addTest( Unit::read1 ); | ||
15 | } | ||
16 | |||
17 | virtual ~Unit() | ||
18 | { | ||
19 | } | ||
20 | |||
21 | void read1() | ||
22 | { | ||
23 | #define FN_TMP ("/tmp/tmpXXXXXXXX") | ||
24 | Bu::FString sFnTmp(FN_TMP); | ||
25 | Bu::File fOut = Bu::File::tempFile( sFnTmp, "wb" ); | ||
26 | const char *data = | ||
27 | "{test: name=\"Bob\"}" | ||
28 | ; | ||
29 | fOut.write(data,strlen(data)); | ||
30 | fOut.close(); | ||
31 | |||
32 | Bu::File fIn(sFnTmp.c_str(), "rb"); | ||
33 | Bu::TafReader tr(fIn); | ||
34 | |||
35 | Bu::TafGroup *tn = tr.readGroup(); | ||
36 | unitTest( !strcmp("Bob", tn->getProperty("name").c_str()) ); | ||
37 | delete tn; | ||
38 | |||
39 | unlink(sFnTmp.c_str()); | ||
40 | #undef FN_TMP | ||
41 | } | ||
42 | }; | ||
43 | |||
44 | int main( int argc, char *argv[] ) | ||
45 | { | ||
46 | return Unit().run( argc, argv ); | ||
47 | } | ||
48 | |||
diff --git a/src/unitsuite.cpp b/src/unitsuite.cpp new file mode 100644 index 0000000..2a28eb5 --- /dev/null +++ b/src/unitsuite.cpp | |||
@@ -0,0 +1,67 @@ | |||
1 | #include "unitsuite.h" | ||
2 | |||
3 | Bu::UnitSuite::UnitSuite() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::UnitSuite::~UnitSuite() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | int Bu::UnitSuite::run( int argc, char *argv[] ) | ||
12 | { | ||
13 | for( TestList::iterator i = lTests.begin(); i != lTests.end(); i++ ) | ||
14 | { | ||
15 | printf("%s: ", i->sName.getStr() ); | ||
16 | fflush( stdout ); | ||
17 | try | ||
18 | { | ||
19 | (this->*(i->fTest))(); | ||
20 | printf("passed.\n"); | ||
21 | } | ||
22 | catch( Failed &e ) | ||
23 | { | ||
24 | if( e.bFile ) | ||
25 | { | ||
26 | printf("unitTest(%s) failed. (%s:%d)\n", | ||
27 | e.str.getStr(), | ||
28 | e.sFile.getStr(), | ||
29 | e.nLine | ||
30 | ); | ||
31 | } | ||
32 | else | ||
33 | { | ||
34 | printf("unitTest(%s) failed.\n", | ||
35 | e.str.getStr() | ||
36 | ); | ||
37 | } | ||
38 | } | ||
39 | catch( ... ) | ||
40 | { | ||
41 | printf("failed with external exception.\n"); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | void Bu::UnitSuite::add( Test fTest, Bu::FString sName ) | ||
49 | { | ||
50 | TestInfo ti; | ||
51 | ti.sName = sName; | ||
52 | long index = ti.sName.rfind("::"); | ||
53 | if( index != -1 ) | ||
54 | { | ||
55 | FString tmp = sSuiteName; | ||
56 | tmp += ti.sName.getStr()+index; | ||
57 | ti.sName = tmp; | ||
58 | } | ||
59 | ti.fTest = fTest; | ||
60 | lTests.push_back( ti ); | ||
61 | } | ||
62 | |||
63 | void Bu::UnitSuite::setName( const FString &sName ) | ||
64 | { | ||
65 | sSuiteName = sName; | ||
66 | } | ||
67 | |||
diff --git a/src/unitsuite.h b/src/unitsuite.h new file mode 100644 index 0000000..578b4cc --- /dev/null +++ b/src/unitsuite.h | |||
@@ -0,0 +1,96 @@ | |||
1 | #ifndef BU_UNIT_SUITE_H | ||
2 | #define BU_UNIT_SUITE_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include <list> | ||
6 | #include "fstring.h" | ||
7 | |||
8 | namespace Bu | ||
9 | { | ||
10 | /** | ||
11 | * Provides a unit testing framework. This is pretty easy to use, probably | ||
12 | * the best way to get started is to use ch to generate a template, or use | ||
13 | * the code below with appropriate tweaks: | ||
14 | *@code | ||
15 | * #include "unitsuite.h" | ||
16 | * | ||
17 | * class Unit : public Bu::UnitSuite | ||
18 | * { | ||
19 | * public: | ||
20 | * Unit() | ||
21 | * { | ||
22 | * setName("Example"); | ||
23 | * addTest( Unit::test ); | ||
24 | * } | ||
25 | * | ||
26 | * virtual ~Unit() { } | ||
27 | * | ||
28 | * // | ||
29 | * // Tests go here | ||
30 | * // | ||
31 | * void test() | ||
32 | * { | ||
33 | * unitTest( 1 == 1 ); | ||
34 | * } | ||
35 | * }; | ||
36 | * | ||
37 | * int main( int argc, char *argv[] ) | ||
38 | * { | ||
39 | * return Unit().run( argc, argv ); | ||
40 | * } | ||
41 | * | ||
42 | @endcode | ||
43 | * The main function can contain other things, but using this one exactly | ||
44 | * makes all of the test suites work exactly the same. Using the optional | ||
45 | * setName at the top of the constructor replaces the class name with the | ||
46 | * chosen name when printing out stats and info. | ||
47 | */ | ||
48 | class UnitSuite | ||
49 | { | ||
50 | public: | ||
51 | UnitSuite(); | ||
52 | virtual ~UnitSuite(); | ||
53 | |||
54 | int run( int argc=0, char *argv[]=NULL ); | ||
55 | |||
56 | typedef void (UnitSuite::*Test)(); | ||
57 | |||
58 | class Failed | ||
59 | { | ||
60 | public: | ||
61 | Failed() : str(""), bFile( false ) { } | ||
62 | Failed( const FString &s ) : str( s ), bFile( false ) { } | ||
63 | Failed( const FString &s, const FString &sFile, int nLine ) : | ||
64 | str( s ), sFile( sFile ), nLine( nLine ), bFile( true ) { } | ||
65 | |||
66 | FString str; | ||
67 | FString sFile; | ||
68 | int nLine; | ||
69 | bool bFile; | ||
70 | }; | ||
71 | |||
72 | protected: | ||
73 | void add( Test fTest, Bu::FString sName ); | ||
74 | void setName( const FString &sName ); | ||
75 | |||
76 | private: | ||
77 | typedef struct TestInfo | ||
78 | { | ||
79 | FString sName; | ||
80 | Test fTest; | ||
81 | } TestInfo; | ||
82 | |||
83 | typedef std::list<TestInfo> TestList; | ||
84 | TestList lTests; | ||
85 | FString sSuiteName; | ||
86 | }; | ||
87 | } | ||
88 | |||
89 | #define addTest( fn ) add( static_cast<Bu::UnitSuite::Test>(&fn), #fn ) | ||
90 | #define unitTest( tst ) if( !(tst) ) \ | ||
91 | { \ | ||
92 | throw Bu::UnitSuite::Failed( #tst, __FILE__, __LINE__ ); \ | ||
93 | } | ||
94 | #define unitFailed( msg ) throw Bu::UnitSuite::Failed(msg, __FILE__, __LINE__); | ||
95 | |||
96 | #endif | ||