diff options
author | Adrian Thurston <thurston@colm.net> | 2020-10-18 11:44:43 -0700 |
---|---|---|
committer | Adrian Thurston <thurston@colm.net> | 2020-10-18 11:44:43 -0700 |
commit | 85b76476de71f43d3eb25d6bef4ee6d84cb71f6c (patch) | |
tree | 65c127fbcf70e62d8a4848be2c9c4ff7d74d86a1 /src/aapl/rope.h | |
parent | 86bb5882a70224a29650ccfa1e46c9b023c2a3ef (diff) | |
download | colm-85b76476de71f43d3eb25d6bef4ee6d84cb71f6c.tar.gz |
lift all source code into src/ dirinto-src
Diffstat (limited to 'src/aapl/rope.h')
-rw-r--r-- | src/aapl/rope.h | 237 |
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 + |