buffer.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. # The contents of this file are subject to the Python Software Foundation
  2. # License Version 2.3 (the License). You may not copy or use this file, in
  3. # either source code or executable form, except in compliance with the License.
  4. # You may obtain a copy of the License at http://www.python.org/license.
  5. #
  6. # Software distributed under the License is distributed on an AS IS basis,
  7. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  8. # for the specific language governing rights and limitations under the
  9. # License.
  10. ctypes = None
  11. try:
  12. import ctypes
  13. except ImportError:
  14. pass
  15. from cStringIO import StringIO
  16. class cStringIO_Buffer(object):
  17. def __init__(self):
  18. self.buffer = StringIO()
  19. for attr in dir(self.buffer):
  20. self.__dict__[attr] = getattr(self.buffer, attr)
  21. def __getattr__(self, attr):
  22. return getattr(self.buffer, attr)
  23. def _slice_to_a_b(self, i):
  24. if not isinstance(i, slice):
  25. if i >= len(self):
  26. raise IndexError("buffer index out of range")
  27. i = slice(i, i+1)
  28. o = self.tell()
  29. if i.start is None:
  30. a = 0
  31. else:
  32. a = i.start
  33. if i.stop is None:
  34. b = o
  35. else:
  36. b = i.stop
  37. if b < 0:
  38. b = o + b
  39. b = max(a, b - a)
  40. return o, a, b
  41. def __setitem__(self, i, d):
  42. o, a, b = self._slice_to_a_b(i)
  43. self.seek(a)
  44. self.write(d)
  45. self.seek(o)
  46. def __getitem__(self, i):
  47. o, a, b = self._slice_to_a_b(i)
  48. self.seek(a)
  49. d = self.read(b)
  50. self.seek(o)
  51. return d
  52. def drop(self, size):
  53. v = self.getvalue()
  54. self.truncate(0)
  55. self.write(buffer(v, size))
  56. def __len__(self):
  57. o = self.tell()
  58. self.seek(0, 2)
  59. x = self.tell()
  60. self.seek(o)
  61. return x
  62. def __str__(self):
  63. return self.getvalue()
  64. Buffer = cStringIO_Buffer
  65. # slow, has dependencies
  66. if False: # ctypes:
  67. class ctypes_Buffer(object):
  68. def __init__(self):
  69. self.length = 32
  70. self.data = ctypes.create_string_buffer(self.length)
  71. self.written = 0
  72. self.offset = 0
  73. def __setitem__(self, i, y):
  74. if isinstance(i, slice):
  75. return self.data.__setslice__(i.start, i.stop, y)
  76. else:
  77. return self.data.__setitem__(i, y)
  78. # TODO: call PyBuffer_FromMemory!
  79. def __getitem__(self, i):
  80. if isinstance(i, slice):
  81. if i.stop < 0:
  82. i = slice(i.start, self.written + i.stop)
  83. return self.data.__getslice__(i.start or 0, i.stop or self.written)
  84. else:
  85. return self.data.__getitem__(i)
  86. def __getattr__(self, attr):
  87. return getattr(self.data, attr)
  88. def __str__(self):
  89. return self.data[:self.written]
  90. def __len__(self):
  91. return self.written
  92. def _oversize(self, l):
  93. o = self.length
  94. while l > self.length:
  95. self.length *= 2
  96. if self.length > o:
  97. d = self.data
  98. self.data = ctypes.create_string_buffer(self.length)
  99. # which is faster?
  100. #self.data[0:self.written] = d[:self.written]
  101. self.data[0:o] = d
  102. def write(self, s):
  103. l = len(s)
  104. self._oversize(self.offset + l)
  105. self.data[self.offset:self.offset + l] = s
  106. self.offset += l
  107. self.written = max(self.written, self.offset)
  108. return l
  109. def seek(self, offset):
  110. self.offset = min(self.written - 1, max(0, offset))
  111. def truncate(self, size=None):
  112. if size is None:
  113. size = self.offset
  114. self.written = size
  115. self.offset = min(size, self.offset)
  116. def drop(self, size):
  117. if size < 0:
  118. raise ValueError("cannot discard negative bytes")
  119. size = min(size, self.written)
  120. new_written = self.written - size
  121. # ow
  122. try:
  123. self.data[:new_written] = self.data[size:self.written]
  124. except ValueError:
  125. print new_written, size, self.written
  126. self.written = new_written
  127. self.offset = min(self.written, self.offset)
  128. Buffer = ctypes_Buffer
  129. b = Buffer()
  130. b.write("ghello")
  131. b.seek(0)
  132. b.write(buffer("ghell"))
  133. b.drop(1)
  134. b[2:3] = 'b'
  135. assert str(b) == "heblo"
  136. assert b[0] == "h"
  137. #print repr(b[:-1])
  138. assert b[:-1] == "hebl"
  139. #assert len(b) <= b.length
  140. assert len(b) == len(str(b))
  141. b.drop(1)
  142. b.seek(0)
  143. b.write('foo')
  144. assert b[0] == 'f'
  145. try:
  146. b[100]
  147. except IndexError:
  148. pass
  149. else:
  150. assert False