Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 128 lines (110 sloc) 3.303 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
"""This is an implementation of a simple buffer. SimpleBuffer just handles
a string of bytes. The clue, is that you can pop data from the beginning
and append data to the end.

It's ideal to use as a network buffer, from which you send data to the socket.
Use this to avoid concatenating or splitting large strings.
"""
import os
try:
    import cStringIO as StringIO
except ImportError:
    import StringIO

# Python 2.4 support: os lacks SEEK_END and friends
try:
    getattr(os, "SEEK_END")
except AttributeError:
    os.SEEK_SET, os.SEEK_CUR, os.SEEK_END = range(3)


class SimpleBuffer(object):
    """
>>> b = SimpleBuffer("abcdef")
>>> b.read_and_consume(3)
'abc'
>>> b.write(None, '')
>>> b.read(0)
''
>>> repr(b)
"<SimpleBuffer of 3 bytes, 6 total size, 'def'>"
>>> str(b)
"<SimpleBuffer of 3 bytes, 6 total size, 'def'>"
>>> b.flush()
>>> b.read(1)
''
"""
    buf = None
    offset = 0
    size = 0

    def __init__(self, data=None):
        self.buf = StringIO.StringIO()
        if data is not None:
            self.write(data)
        self.buf.seek(0, os.SEEK_END)

    def write(self, *data_strings):
        """
Append given strings to the buffer.
"""
        for data in data_strings:
            if not data:
                continue
            self.buf.write(data)
            self.size += len(data)

    def read(self, size=None):
        """
Read the data from the buffer, at most 'size' bytes.
"""
        if size is 0:
            return ''

        self.buf.seek(self.offset)

        if size is None:
            data = self.buf.read()
        else:
            data = self.buf.read(size)

        self.buf.seek(0, os.SEEK_END)
        return data

    def consume(self, size):
        """
Move pointer and discard first 'size' bytes.
"""
        self.offset += size
        self.size -= size
        # GC old StringIO instance and free memory used by it.
        if self.size == 0 and self.offset > 65536:
            self.buf.close()
            del self.buf
            self.buf = StringIO.StringIO()
            self.offset = 0

    def read_and_consume(self, size):
        """
Read up to 'size' bytes, also remove it from the buffer.
"""
        assert(self.size >= size)
        data = self.read(size)
        self.consume(size)
        return data

    def send_to_socket(self, sd):
        """
Faster way of sending buffer data to socket 'sd'.
"""
        self.buf.seek(self.offset)
        r = sd.send(self.buf.read())
        self.buf.seek(0, os.SEEK_END)
        self.offset += r
        self.size -= r
        if self.offset > 524288 and self.size == 0:
            self.consume(0)
        return r

    def flush(self):
        """
Remove all the data from buffer.
"""
        self.consume(self.size)

    def __nonzero__(self):
        """Are we empty?"""
        return self.size > 0

    def __len__(self):
        return self.size

    def __str__(self):
        return self.__repr__()

    def __repr__(self):
        return '<SimpleBuffer of %i bytes, %i total size, %r%s>' % \
                    (self.size, self.size + self.offset, self.read(16),
                    (self.size > 16) and '...' or '')
Something went wrong with that request. Please try again.