SingleChunkBuffer.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* Copyright 2010-present MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. namespace MongoDB.Bson.IO
  17. {
  18. /// <summary>
  19. /// An IByteBuffer that is backed by a single chunk.
  20. /// </summary>
  21. public sealed class SingleChunkBuffer : IByteBuffer
  22. {
  23. // private fields
  24. private IBsonChunk _chunk;
  25. private bool _disposed;
  26. private bool _isReadOnly;
  27. private int _length;
  28. // constructors
  29. /// <summary>
  30. /// Initializes a new instance of the <see cref="SingleChunkBuffer"/> class.
  31. /// </summary>
  32. /// <param name="chunk">The chuns.</param>
  33. /// <param name="length">The length.</param>
  34. /// <param name="isReadOnly">Whether the buffer is read only.</param>
  35. public SingleChunkBuffer(IBsonChunk chunk, int length, bool isReadOnly = false)
  36. {
  37. if (chunk == null)
  38. {
  39. throw new ArgumentNullException("chunk");
  40. }
  41. if (length < 0 || length > chunk.Bytes.Count)
  42. {
  43. throw new ArgumentOutOfRangeException("length");
  44. }
  45. _chunk = chunk;
  46. _length = length;
  47. _isReadOnly = isReadOnly;
  48. }
  49. // public properties
  50. /// <inheritdoc/>
  51. public int Capacity
  52. {
  53. get
  54. {
  55. ThrowIfDisposed();
  56. return _isReadOnly ? _length : _chunk.Bytes.Count;
  57. }
  58. }
  59. /// <inheritdoc/>
  60. public bool IsReadOnly
  61. {
  62. get
  63. {
  64. ThrowIfDisposed();
  65. return _isReadOnly;
  66. }
  67. }
  68. /// <inheritdoc/>
  69. public int Length
  70. {
  71. get
  72. {
  73. ThrowIfDisposed();
  74. return _length;
  75. }
  76. set
  77. {
  78. ThrowIfDisposed();
  79. if (value < 0 || value > _chunk.Bytes.Count)
  80. {
  81. throw new ArgumentOutOfRangeException("value");
  82. }
  83. EnsureIsWritable();
  84. _length = value;
  85. }
  86. }
  87. // public methods
  88. /// <inheritdoc/>
  89. public ArraySegment<byte> AccessBackingBytes(int position)
  90. {
  91. ThrowIfDisposed();
  92. if (position < 0 || position > _length)
  93. {
  94. throw new ArgumentOutOfRangeException("position");
  95. }
  96. var segment = _chunk.Bytes;
  97. return new ArraySegment<byte>(segment.Array, segment.Offset + position, _length - position);
  98. }
  99. /// <inheritdoc/>
  100. public void Clear(int position, int count)
  101. {
  102. ThrowIfDisposed();
  103. if (position < 0 || position > _length)
  104. {
  105. throw new ArgumentOutOfRangeException("position");
  106. }
  107. if (count < 0 || position + count > _length)
  108. {
  109. throw new ArgumentOutOfRangeException("count");
  110. }
  111. EnsureIsWritable();
  112. var segment = _chunk.Bytes;
  113. Array.Clear(segment.Array, segment.Offset + position, count);
  114. }
  115. /// <inheritdoc/>
  116. public void Dispose()
  117. {
  118. if (!_disposed)
  119. {
  120. _disposed = true;
  121. _chunk.Dispose();
  122. _chunk = null;
  123. }
  124. }
  125. /// <inheritdoc/>
  126. public void EnsureCapacity(int minimumCapacity)
  127. {
  128. if (minimumCapacity < 0)
  129. {
  130. throw new ArgumentOutOfRangeException("minimumCapacity");
  131. }
  132. ThrowIfDisposed();
  133. EnsureIsWritable();
  134. if (_chunk.Bytes.Count < minimumCapacity)
  135. {
  136. throw new NotSupportedException("Capacity cannot be expanded for a SingleChunkBuffer.");
  137. }
  138. }
  139. /// <inheritdoc/>
  140. public byte GetByte(int position)
  141. {
  142. ThrowIfDisposed();
  143. if (position < 0 || position > _length)
  144. {
  145. throw new ArgumentOutOfRangeException("position");
  146. }
  147. var segment = _chunk.Bytes;
  148. return segment.Array[segment.Offset + position];
  149. }
  150. /// <inheritdoc/>
  151. public void GetBytes(int position, byte[] destination, int offset, int count)
  152. {
  153. ThrowIfDisposed();
  154. if (position < 0 || position > _length)
  155. {
  156. throw new ArgumentOutOfRangeException("position");
  157. }
  158. if (destination == null)
  159. {
  160. throw new ArgumentNullException("destination");
  161. }
  162. if (offset < 0 || offset > destination.Length)
  163. {
  164. throw new ArgumentOutOfRangeException("offset");
  165. }
  166. if (count < 0 || position + count > _length || offset + count > destination.Length)
  167. {
  168. throw new ArgumentOutOfRangeException("count");
  169. }
  170. var segment = _chunk.Bytes;
  171. Buffer.BlockCopy(segment.Array, segment.Offset + position, destination, offset, count);
  172. }
  173. /// <inheritdoc/>
  174. public IByteBuffer GetSlice(int position, int length)
  175. {
  176. ThrowIfDisposed();
  177. if (position < 0 || position > _length)
  178. {
  179. throw new ArgumentOutOfRangeException("position");
  180. }
  181. if (length < 0 || position + length > _length)
  182. {
  183. throw new ArgumentOutOfRangeException("length");
  184. }
  185. EnsureIsReadOnly();
  186. var forkedBuffer = new SingleChunkBuffer(_chunk.Fork(), _length, isReadOnly: true);
  187. return new ByteBufferSlice(forkedBuffer, position, length);
  188. }
  189. /// <inheritdoc/>
  190. public void MakeReadOnly()
  191. {
  192. ThrowIfDisposed();
  193. _isReadOnly = true;
  194. }
  195. /// <inheritdoc/>
  196. public void SetByte(int position, byte value)
  197. {
  198. ThrowIfDisposed();
  199. if (position < 0 || position > _length)
  200. {
  201. throw new ArgumentOutOfRangeException("position");
  202. }
  203. EnsureIsWritable();
  204. var segment = _chunk.Bytes;
  205. segment.Array[segment.Offset + position] = value;
  206. }
  207. /// <inheritdoc/>
  208. public void SetBytes(int position, byte[] source, int offset, int count)
  209. {
  210. ThrowIfDisposed();
  211. if (position < 0 || position > _length)
  212. {
  213. throw new ArgumentOutOfRangeException("position");
  214. }
  215. if (source == null)
  216. {
  217. throw new ArgumentNullException("source");
  218. }
  219. if (offset < 0 || offset > source.Length)
  220. {
  221. throw new ArgumentOutOfRangeException("offset");
  222. }
  223. if (count < 0 || position + count > _length || offset + count > source.Length)
  224. {
  225. throw new ArgumentOutOfRangeException("count");
  226. }
  227. EnsureIsWritable();
  228. var segment = _chunk.Bytes;
  229. Buffer.BlockCopy(source, offset, segment.Array, segment.Offset + position, count);
  230. }
  231. // private methods
  232. private void EnsureIsReadOnly()
  233. {
  234. if (!_isReadOnly)
  235. {
  236. throw new InvalidOperationException("MultiChunkBuffer is not read only.");
  237. }
  238. }
  239. private void EnsureIsWritable()
  240. {
  241. if (_isReadOnly)
  242. {
  243. throw new InvalidOperationException("MultiChunkBuffer is not writable.");
  244. }
  245. }
  246. private void ThrowIfDisposed()
  247. {
  248. if (_disposed)
  249. {
  250. throw new ObjectDisposedException(GetType().Name);
  251. }
  252. }
  253. }
  254. }