/src/ProtocolBuffers/CodedOutputStream.ComputeSize.cs

https://code.google.com/p/protobuf-csharp-port/ · C# · 653 lines · 381 code · 50 blank · 222 comment · 32 complexity · 632d0cde6bf48e063a3a9eb4164e8d5a MD5 · raw file

  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // http://github.com/jskeet/dotnet-protobufs/
  5. // Original C++/Java/Python code:
  6. // http://code.google.com/p/protobuf/
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. //
  12. // * Redistributions of source code must retain the above copyright
  13. // notice, this list of conditions and the following disclaimer.
  14. // * Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following disclaimer
  16. // in the documentation and/or other materials provided with the
  17. // distribution.
  18. // * Neither the name of Google Inc. nor the names of its
  19. // contributors may be used to endorse or promote products derived from
  20. // this software without specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. #endregion
  34. using System;
  35. using System.Globalization;
  36. using System.Text;
  37. using Google.ProtocolBuffers.Descriptors;
  38. namespace Google.ProtocolBuffers
  39. {
  40. // This part of CodedOutputStream provides all the static entry points that are used
  41. // by generated code and internally to compute the size of messages prior to being
  42. // written to an instance of CodedOutputStream.
  43. public sealed partial class CodedOutputStream
  44. {
  45. private const int LittleEndian64Size = 8;
  46. private const int LittleEndian32Size = 4;
  47. /// <summary>
  48. /// Compute the number of bytes that would be needed to encode a
  49. /// double field, including the tag.
  50. /// </summary>
  51. public static int ComputeDoubleSize(int fieldNumber, double value)
  52. {
  53. return ComputeTagSize(fieldNumber) + LittleEndian64Size;
  54. }
  55. /// <summary>
  56. /// Compute the number of bytes that would be needed to encode a
  57. /// float field, including the tag.
  58. /// </summary>
  59. public static int ComputeFloatSize(int fieldNumber, float value)
  60. {
  61. return ComputeTagSize(fieldNumber) + LittleEndian32Size;
  62. }
  63. /// <summary>
  64. /// Compute the number of bytes that would be needed to encode a
  65. /// uint64 field, including the tag.
  66. /// </summary>
  67. [CLSCompliant(false)]
  68. public static int ComputeUInt64Size(int fieldNumber, ulong value)
  69. {
  70. return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(value);
  71. }
  72. /// <summary>
  73. /// Compute the number of bytes that would be needed to encode an
  74. /// int64 field, including the tag.
  75. /// </summary>
  76. public static int ComputeInt64Size(int fieldNumber, long value)
  77. {
  78. return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size((ulong) value);
  79. }
  80. /// <summary>
  81. /// Compute the number of bytes that would be needed to encode an
  82. /// int32 field, including the tag.
  83. /// </summary>
  84. public static int ComputeInt32Size(int fieldNumber, int value)
  85. {
  86. if (value >= 0)
  87. {
  88. return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint) value);
  89. }
  90. else
  91. {
  92. // Must sign-extend.
  93. return ComputeTagSize(fieldNumber) + 10;
  94. }
  95. }
  96. /// <summary>
  97. /// Compute the number of bytes that would be needed to encode a
  98. /// fixed64 field, including the tag.
  99. /// </summary>
  100. [CLSCompliant(false)]
  101. public static int ComputeFixed64Size(int fieldNumber, ulong value)
  102. {
  103. return ComputeTagSize(fieldNumber) + LittleEndian64Size;
  104. }
  105. /// <summary>
  106. /// Compute the number of bytes that would be needed to encode a
  107. /// fixed32 field, including the tag.
  108. /// </summary>
  109. [CLSCompliant(false)]
  110. public static int ComputeFixed32Size(int fieldNumber, uint value)
  111. {
  112. return ComputeTagSize(fieldNumber) + LittleEndian32Size;
  113. }
  114. /// <summary>
  115. /// Compute the number of bytes that would be needed to encode a
  116. /// bool field, including the tag.
  117. /// </summary>
  118. public static int ComputeBoolSize(int fieldNumber, bool value)
  119. {
  120. return ComputeTagSize(fieldNumber) + 1;
  121. }
  122. /// <summary>
  123. /// Compute the number of bytes that would be needed to encode a
  124. /// string field, including the tag.
  125. /// </summary>
  126. public static int ComputeStringSize(int fieldNumber, String value)
  127. {
  128. int byteArraySize = Encoding.UTF8.GetByteCount(value);
  129. return ComputeTagSize(fieldNumber) +
  130. ComputeRawVarint32Size((uint) byteArraySize) +
  131. byteArraySize;
  132. }
  133. /// <summary>
  134. /// Compute the number of bytes that would be needed to encode a
  135. /// group field, including the tag.
  136. /// </summary>
  137. public static int ComputeGroupSize(int fieldNumber, IMessageLite value)
  138. {
  139. return ComputeTagSize(fieldNumber)*2 + value.SerializedSize;
  140. }
  141. /// <summary>
  142. /// Compute the number of bytes that would be needed to encode a
  143. /// group field represented by an UnknownFieldSet, including the tag.
  144. /// </summary>
  145. [Obsolete]
  146. public static int ComputeUnknownGroupSize(int fieldNumber,
  147. IMessageLite value)
  148. {
  149. return ComputeTagSize(fieldNumber)*2 + value.SerializedSize;
  150. }
  151. /// <summary>
  152. /// Compute the number of bytes that would be needed to encode an
  153. /// embedded message field, including the tag.
  154. /// </summary>
  155. public static int ComputeMessageSize(int fieldNumber, IMessageLite value)
  156. {
  157. int size = value.SerializedSize;
  158. return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint) size) + size;
  159. }
  160. /// <summary>
  161. /// Compute the number of bytes that would be needed to encode a
  162. /// bytes field, including the tag.
  163. /// </summary>
  164. public static int ComputeBytesSize(int fieldNumber, ByteString value)
  165. {
  166. return ComputeTagSize(fieldNumber) +
  167. ComputeRawVarint32Size((uint) value.Length) +
  168. value.Length;
  169. }
  170. /// <summary>
  171. /// Compute the number of bytes that would be needed to encode a
  172. /// uint32 field, including the tag.
  173. /// </summary>
  174. [CLSCompliant(false)]
  175. public static int ComputeUInt32Size(int fieldNumber, uint value)
  176. {
  177. return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(value);
  178. }
  179. /// <summary>
  180. /// Compute the number of bytes that would be needed to encode a
  181. /// enum field, including the tag. The caller is responsible for
  182. /// converting the enum value to its numeric value.
  183. /// </summary>
  184. public static int ComputeEnumSize(int fieldNumber, int value)
  185. {
  186. return ComputeTagSize(fieldNumber) + ComputeEnumSizeNoTag(value);
  187. }
  188. /// <summary>
  189. /// Compute the number of bytes that would be needed to encode an
  190. /// sfixed32 field, including the tag.
  191. /// </summary>
  192. public static int ComputeSFixed32Size(int fieldNumber, int value)
  193. {
  194. return ComputeTagSize(fieldNumber) + LittleEndian32Size;
  195. }
  196. /// <summary>
  197. /// Compute the number of bytes that would be needed to encode an
  198. /// sfixed64 field, including the tag.
  199. /// </summary>
  200. public static int ComputeSFixed64Size(int fieldNumber, long value)
  201. {
  202. return ComputeTagSize(fieldNumber) + LittleEndian64Size;
  203. }
  204. /// <summary>
  205. /// Compute the number of bytes that would be needed to encode an
  206. /// sint32 field, including the tag.
  207. /// </summary>
  208. public static int ComputeSInt32Size(int fieldNumber, int value)
  209. {
  210. return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(EncodeZigZag32(value));
  211. }
  212. /// <summary>
  213. /// Compute the number of bytes that would be needed to encode an
  214. /// sint64 field, including the tag.
  215. /// </summary>
  216. public static int ComputeSInt64Size(int fieldNumber, long value)
  217. {
  218. return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(EncodeZigZag64(value));
  219. }
  220. /// <summary>
  221. /// Compute the number of bytes that would be needed to encode a
  222. /// double field, including the tag.
  223. /// </summary>
  224. public static int ComputeDoubleSizeNoTag(double value)
  225. {
  226. return LittleEndian64Size;
  227. }
  228. /// <summary>
  229. /// Compute the number of bytes that would be needed to encode a
  230. /// float field, including the tag.
  231. /// </summary>
  232. public static int ComputeFloatSizeNoTag(float value)
  233. {
  234. return LittleEndian32Size;
  235. }
  236. /// <summary>
  237. /// Compute the number of bytes that would be needed to encode a
  238. /// uint64 field, including the tag.
  239. /// </summary>
  240. [CLSCompliant(false)]
  241. public static int ComputeUInt64SizeNoTag(ulong value)
  242. {
  243. return ComputeRawVarint64Size(value);
  244. }
  245. /// <summary>
  246. /// Compute the number of bytes that would be needed to encode an
  247. /// int64 field, including the tag.
  248. /// </summary>
  249. public static int ComputeInt64SizeNoTag(long value)
  250. {
  251. return ComputeRawVarint64Size((ulong) value);
  252. }
  253. /// <summary>
  254. /// Compute the number of bytes that would be needed to encode an
  255. /// int32 field, including the tag.
  256. /// </summary>
  257. public static int ComputeInt32SizeNoTag(int value)
  258. {
  259. if (value >= 0)
  260. {
  261. return ComputeRawVarint32Size((uint) value);
  262. }
  263. else
  264. {
  265. // Must sign-extend.
  266. return 10;
  267. }
  268. }
  269. /// <summary>
  270. /// Compute the number of bytes that would be needed to encode a
  271. /// fixed64 field, including the tag.
  272. /// </summary>
  273. [CLSCompliant(false)]
  274. public static int ComputeFixed64SizeNoTag(ulong value)
  275. {
  276. return LittleEndian64Size;
  277. }
  278. /// <summary>
  279. /// Compute the number of bytes that would be needed to encode a
  280. /// fixed32 field, including the tag.
  281. /// </summary>
  282. [CLSCompliant(false)]
  283. public static int ComputeFixed32SizeNoTag(uint value)
  284. {
  285. return LittleEndian32Size;
  286. }
  287. /// <summary>
  288. /// Compute the number of bytes that would be needed to encode a
  289. /// bool field, including the tag.
  290. /// </summary>
  291. public static int ComputeBoolSizeNoTag(bool value)
  292. {
  293. return 1;
  294. }
  295. /// <summary>
  296. /// Compute the number of bytes that would be needed to encode a
  297. /// string field, including the tag.
  298. /// </summary>
  299. public static int ComputeStringSizeNoTag(String value)
  300. {
  301. int byteArraySize = Encoding.UTF8.GetByteCount(value);
  302. return ComputeRawVarint32Size((uint) byteArraySize) +
  303. byteArraySize;
  304. }
  305. /// <summary>
  306. /// Compute the number of bytes that would be needed to encode a
  307. /// group field, including the tag.
  308. /// </summary>
  309. public static int ComputeGroupSizeNoTag(IMessageLite value)
  310. {
  311. return value.SerializedSize;
  312. }
  313. /// <summary>
  314. /// Compute the number of bytes that would be needed to encode a
  315. /// group field represented by an UnknownFieldSet, including the tag.
  316. /// </summary>
  317. [Obsolete]
  318. public static int ComputeUnknownGroupSizeNoTag(IMessageLite value)
  319. {
  320. return value.SerializedSize;
  321. }
  322. /// <summary>
  323. /// Compute the number of bytes that would be needed to encode an
  324. /// embedded message field, including the tag.
  325. /// </summary>
  326. public static int ComputeMessageSizeNoTag(IMessageLite value)
  327. {
  328. int size = value.SerializedSize;
  329. return ComputeRawVarint32Size((uint) size) + size;
  330. }
  331. /// <summary>
  332. /// Compute the number of bytes that would be needed to encode a
  333. /// bytes field, including the tag.
  334. /// </summary>
  335. public static int ComputeBytesSizeNoTag(ByteString value)
  336. {
  337. return ComputeRawVarint32Size((uint) value.Length) +
  338. value.Length;
  339. }
  340. /// <summary>
  341. /// Compute the number of bytes that would be needed to encode a
  342. /// uint32 field, including the tag.
  343. /// </summary>
  344. [CLSCompliant(false)]
  345. public static int ComputeUInt32SizeNoTag(uint value)
  346. {
  347. return ComputeRawVarint32Size(value);
  348. }
  349. /// <summary>
  350. /// Compute the number of bytes that would be needed to encode a
  351. /// enum field, including the tag. The caller is responsible for
  352. /// converting the enum value to its numeric value.
  353. /// </summary>
  354. public static int ComputeEnumSizeNoTag(int value)
  355. {
  356. return ComputeInt32SizeNoTag(value);
  357. }
  358. /// <summary>
  359. /// Compute the number of bytes that would be needed to encode an
  360. /// sfixed32 field, including the tag.
  361. /// </summary>
  362. public static int ComputeSFixed32SizeNoTag(int value)
  363. {
  364. return LittleEndian32Size;
  365. }
  366. /// <summary>
  367. /// Compute the number of bytes that would be needed to encode an
  368. /// sfixed64 field, including the tag.
  369. /// </summary>
  370. public static int ComputeSFixed64SizeNoTag(long value)
  371. {
  372. return LittleEndian64Size;
  373. }
  374. /// <summary>
  375. /// Compute the number of bytes that would be needed to encode an
  376. /// sint32 field, including the tag.
  377. /// </summary>
  378. public static int ComputeSInt32SizeNoTag(int value)
  379. {
  380. return ComputeRawVarint32Size(EncodeZigZag32(value));
  381. }
  382. /// <summary>
  383. /// Compute the number of bytes that would be needed to encode an
  384. /// sint64 field, including the tag.
  385. /// </summary>
  386. public static int ComputeSInt64SizeNoTag(long value)
  387. {
  388. return ComputeRawVarint64Size(EncodeZigZag64(value));
  389. }
  390. /*
  391. * Compute the number of bytes that would be needed to encode a
  392. * MessageSet extension to the stream. For historical reasons,
  393. * the wire format differs from normal fields.
  394. */
  395. /// <summary>
  396. /// Compute the number of bytes that would be needed to encode a
  397. /// MessageSet extension to the stream. For historical reasons,
  398. /// the wire format differs from normal fields.
  399. /// </summary>
  400. public static int ComputeMessageSetExtensionSize(int fieldNumber, IMessageLite value)
  401. {
  402. return ComputeTagSize(WireFormat.MessageSetField.Item)*2 +
  403. ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
  404. ComputeMessageSize(WireFormat.MessageSetField.Message, value);
  405. }
  406. /// <summary>
  407. /// Compute the number of bytes that would be needed to encode an
  408. /// unparsed MessageSet extension field to the stream. For
  409. /// historical reasons, the wire format differs from normal fields.
  410. /// </summary>
  411. public static int ComputeRawMessageSetExtensionSize(int fieldNumber, ByteString value)
  412. {
  413. return ComputeTagSize(WireFormat.MessageSetField.Item)*2 +
  414. ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
  415. ComputeBytesSize(WireFormat.MessageSetField.Message, value);
  416. }
  417. /// <summary>
  418. /// Compute the number of bytes that would be needed to encode a varint.
  419. /// </summary>
  420. [CLSCompliant(false)]
  421. public static int ComputeRawVarint32Size(uint value)
  422. {
  423. if ((value & (0xffffffff << 7)) == 0)
  424. {
  425. return 1;
  426. }
  427. if ((value & (0xffffffff << 14)) == 0)
  428. {
  429. return 2;
  430. }
  431. if ((value & (0xffffffff << 21)) == 0)
  432. {
  433. return 3;
  434. }
  435. if ((value & (0xffffffff << 28)) == 0)
  436. {
  437. return 4;
  438. }
  439. return 5;
  440. }
  441. /// <summary>
  442. /// Compute the number of bytes that would be needed to encode a varint.
  443. /// </summary>
  444. [CLSCompliant(false)]
  445. public static int ComputeRawVarint64Size(ulong value)
  446. {
  447. if ((value & (0xffffffffffffffffL << 7)) == 0)
  448. {
  449. return 1;
  450. }
  451. if ((value & (0xffffffffffffffffL << 14)) == 0)
  452. {
  453. return 2;
  454. }
  455. if ((value & (0xffffffffffffffffL << 21)) == 0)
  456. {
  457. return 3;
  458. }
  459. if ((value & (0xffffffffffffffffL << 28)) == 0)
  460. {
  461. return 4;
  462. }
  463. if ((value & (0xffffffffffffffffL << 35)) == 0)
  464. {
  465. return 5;
  466. }
  467. if ((value & (0xffffffffffffffffL << 42)) == 0)
  468. {
  469. return 6;
  470. }
  471. if ((value & (0xffffffffffffffffL << 49)) == 0)
  472. {
  473. return 7;
  474. }
  475. if ((value & (0xffffffffffffffffL << 56)) == 0)
  476. {
  477. return 8;
  478. }
  479. if ((value & (0xffffffffffffffffL << 63)) == 0)
  480. {
  481. return 9;
  482. }
  483. return 10;
  484. }
  485. /// <summary>
  486. /// Compute the number of bytes that would be needed to encode a
  487. /// field of arbitrary type, including the tag, to the stream.
  488. /// </summary>
  489. public static int ComputeFieldSize(FieldType fieldType, int fieldNumber, Object value)
  490. {
  491. switch (fieldType)
  492. {
  493. case FieldType.Double:
  494. return ComputeDoubleSize(fieldNumber, (double) value);
  495. case FieldType.Float:
  496. return ComputeFloatSize(fieldNumber, (float) value);
  497. case FieldType.Int64:
  498. return ComputeInt64Size(fieldNumber, (long) value);
  499. case FieldType.UInt64:
  500. return ComputeUInt64Size(fieldNumber, (ulong) value);
  501. case FieldType.Int32:
  502. return ComputeInt32Size(fieldNumber, (int) value);
  503. case FieldType.Fixed64:
  504. return ComputeFixed64Size(fieldNumber, (ulong) value);
  505. case FieldType.Fixed32:
  506. return ComputeFixed32Size(fieldNumber, (uint) value);
  507. case FieldType.Bool:
  508. return ComputeBoolSize(fieldNumber, (bool) value);
  509. case FieldType.String:
  510. return ComputeStringSize(fieldNumber, (string) value);
  511. case FieldType.Group:
  512. return ComputeGroupSize(fieldNumber, (IMessageLite) value);
  513. case FieldType.Message:
  514. return ComputeMessageSize(fieldNumber, (IMessageLite) value);
  515. case FieldType.Bytes:
  516. return ComputeBytesSize(fieldNumber, (ByteString) value);
  517. case FieldType.UInt32:
  518. return ComputeUInt32Size(fieldNumber, (uint) value);
  519. case FieldType.SFixed32:
  520. return ComputeSFixed32Size(fieldNumber, (int) value);
  521. case FieldType.SFixed64:
  522. return ComputeSFixed64Size(fieldNumber, (long) value);
  523. case FieldType.SInt32:
  524. return ComputeSInt32Size(fieldNumber, (int) value);
  525. case FieldType.SInt64:
  526. return ComputeSInt64Size(fieldNumber, (long) value);
  527. case FieldType.Enum:
  528. if (value is Enum)
  529. {
  530. return ComputeEnumSize(fieldNumber, ((IConvertible) value).ToInt32(CultureInfo.InvariantCulture));
  531. }
  532. else
  533. {
  534. return ComputeEnumSize(fieldNumber, ((IEnumLite) value).Number);
  535. }
  536. default:
  537. throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
  538. }
  539. }
  540. /// <summary>
  541. /// Compute the number of bytes that would be needed to encode a
  542. /// field of arbitrary type, excluding the tag, to the stream.
  543. /// </summary>
  544. public static int ComputeFieldSizeNoTag(FieldType fieldType, Object value)
  545. {
  546. switch (fieldType)
  547. {
  548. case FieldType.Double:
  549. return ComputeDoubleSizeNoTag((double) value);
  550. case FieldType.Float:
  551. return ComputeFloatSizeNoTag((float) value);
  552. case FieldType.Int64:
  553. return ComputeInt64SizeNoTag((long) value);
  554. case FieldType.UInt64:
  555. return ComputeUInt64SizeNoTag((ulong) value);
  556. case FieldType.Int32:
  557. return ComputeInt32SizeNoTag((int) value);
  558. case FieldType.Fixed64:
  559. return ComputeFixed64SizeNoTag((ulong) value);
  560. case FieldType.Fixed32:
  561. return ComputeFixed32SizeNoTag((uint) value);
  562. case FieldType.Bool:
  563. return ComputeBoolSizeNoTag((bool) value);
  564. case FieldType.String:
  565. return ComputeStringSizeNoTag((string) value);
  566. case FieldType.Group:
  567. return ComputeGroupSizeNoTag((IMessageLite) value);
  568. case FieldType.Message:
  569. return ComputeMessageSizeNoTag((IMessageLite) value);
  570. case FieldType.Bytes:
  571. return ComputeBytesSizeNoTag((ByteString) value);
  572. case FieldType.UInt32:
  573. return ComputeUInt32SizeNoTag((uint) value);
  574. case FieldType.SFixed32:
  575. return ComputeSFixed32SizeNoTag((int) value);
  576. case FieldType.SFixed64:
  577. return ComputeSFixed64SizeNoTag((long) value);
  578. case FieldType.SInt32:
  579. return ComputeSInt32SizeNoTag((int) value);
  580. case FieldType.SInt64:
  581. return ComputeSInt64SizeNoTag((long) value);
  582. case FieldType.Enum:
  583. if (value is Enum)
  584. {
  585. return ComputeEnumSizeNoTag(((IConvertible) value).ToInt32(CultureInfo.InvariantCulture));
  586. }
  587. else
  588. {
  589. return ComputeEnumSizeNoTag(((IEnumLite) value).Number);
  590. }
  591. default:
  592. throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
  593. }
  594. }
  595. /// <summary>
  596. /// Compute the number of bytes that would be needed to encode a tag.
  597. /// </summary>
  598. public static int ComputeTagSize(int fieldNumber)
  599. {
  600. return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));
  601. }
  602. }
  603. }