summaryrefslogtreecommitdiff
path: root/src/aapl/rope.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/aapl/rope.h')
-rw-r--r--src/aapl/rope.h237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/aapl/rope.h b/src/aapl/rope.h
new file mode 100644
index 00000000..7a5e7b58
--- /dev/null
+++ b/src/aapl/rope.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2016 Adrian Thurston <thurston@colm.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _AAPL_ROPE_H
+#define _AAPL_ROPE_H
+
+#include <string.h>
+#include <iostream>
+#include <stdio.h>
+
+struct RopeBlock
+{
+ static const int BLOCK_SZ = 8192;
+
+ RopeBlock()
+ :
+ size(BLOCK_SZ),
+ hoff(0),
+ toff(0)
+ {
+ }
+
+ int size;
+ int hoff;
+ int toff;
+ RopeBlock *next;
+};
+
+struct Rope
+{
+ Rope()
+ :
+ hblk(0),
+ tblk(0),
+ ropeLen(0)
+ {
+ }
+
+ /* Write to the tail block, at tail offset. */
+ RopeBlock *hblk;
+ RopeBlock *tblk;
+
+ /* Number of bytes in rope. */
+ int ropeLen;
+
+ RopeBlock *allocateBlock( int supporting )
+ {
+ int size = ( supporting > RopeBlock::BLOCK_SZ ) ? supporting : RopeBlock::BLOCK_SZ;
+ char *bd = new char[sizeof(RopeBlock) + size];
+ RopeBlock *block = (RopeBlock*) bd;
+ block->size = size;
+ block->hoff = 0;
+ block->toff = 0;
+ block->next = 0;
+ return block;
+ }
+
+ char *data( RopeBlock *rb )
+ { return (char*)rb + sizeof( RopeBlock ) + rb->hoff; }
+
+ char *writeTo( RopeBlock *rb )
+ { return (char*)rb + sizeof( RopeBlock ) + rb->toff; }
+
+ int length( RopeBlock *rb )
+ { return rb->toff - rb->hoff; }
+
+ int length()
+ { return ropeLen; }
+
+ int available( RopeBlock *rb )
+ { return rb->size - rb->toff; }
+
+ char *append( const char *src, int len )
+ {
+ if ( tblk == 0 ) {
+ /* There are no blocks. */
+ hblk = tblk = allocateBlock( len );
+ }
+ else {
+ int avail = available( tblk );
+
+ /* Move to the next block? */
+ if ( len > avail ) {
+ RopeBlock *block = allocateBlock( len );
+ tblk->next = block;
+ tblk = block;
+ }
+ }
+
+ char *ret = writeTo(tblk);
+ tblk->toff += len;
+ ropeLen += len;
+
+ if ( src != 0 )
+ memcpy( ret, src, len );
+ return ret;
+ }
+
+ char *appendBlock( int len )
+ {
+ if ( tblk == 0 ) {
+ /* There are no blocks. */
+ hblk = tblk = allocateBlock( len );
+ }
+ else {
+ RopeBlock *block = allocateBlock( len );
+ tblk->next = block;
+ tblk = block;
+ }
+
+ char *ret = writeTo(tblk);
+ tblk->toff += len;
+ ropeLen += len;
+ return ret;
+ }
+
+ /* Transfer data from other. Leaves it empty. */
+ void append( Rope &other )
+ {
+ if ( hblk == 0 ) {
+ transfer( other );
+ }
+ else if ( other.hblk == 0 ) {
+ /* nothing to do, other list empty. */
+ }
+ else {
+ tblk->next = other.hblk;
+ tblk = other.tblk;
+ ropeLen += other.ropeLen;
+ }
+
+ other.abandon();
+ }
+
+ void empty()
+ {
+ RopeBlock *blk = hblk;
+ while ( blk != 0 ) {
+ RopeBlock *next = blk->next;
+ delete[] (char*)blk;
+ blk = next;
+ }
+
+ hblk = 0;
+ tblk = 0;
+ ropeLen = 0;
+ }
+
+ void abandon()
+ {
+ hblk = 0;
+ tblk = 0;
+ ropeLen = 0;
+ }
+
+ void transfer( Rope &from )
+ {
+ empty();
+
+ this->hblk = from.hblk;
+ this->tblk = from.tblk;
+ this->ropeLen = from.ropeLen;
+
+ from.hblk = from.tblk = 0;
+ from.ropeLen = 0;
+ }
+};
+
+
+/*
+ * StringStream for appending to streams with an ostream.
+ */
+struct RopeOutBuf
+:
+ public std::streambuf
+{
+ RopeOutBuf( Rope &r )
+ :
+ r(r)
+ {
+ }
+
+ int_type overflow( int_type c )
+ {
+ if ( c != EOF ) {
+ char z = c;
+ r.append( &z, 1 );
+ }
+ return c;
+ }
+
+ std::streamsize xsputn( const char *data, std::streamsize num )
+ {
+ r.append( data, num );
+ return num;
+ }
+
+ Rope &r;
+};
+
+struct RopeStream
+:
+ public std::ostream
+{
+ RopeStream( Rope &r )
+ :
+ std::ostream( 0 ),
+ buf( r )
+ {
+ rdbuf( &buf );
+ }
+
+ RopeOutBuf buf;
+};
+
+
+#endif
+