string-builder.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /**
  2. * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * Adapted from CIFTools.js (https://github.com/dsehnal/CIFTools.js)
  5. *
  6. * @author David Sehnal <david.sehnal@gmail.com>
  7. */
  8. interface StringBuilder {
  9. current: string[],
  10. offset: number,
  11. capacity: number,
  12. chunks: string[]
  13. }
  14. namespace StringBuilder {
  15. export function create(chunkCapacity = 512): StringBuilder {
  16. return {
  17. current: [],
  18. offset: 0,
  19. capacity: chunkCapacity,
  20. chunks: []
  21. };
  22. }
  23. export function getString(builder: StringBuilder) {
  24. if (!builder.chunks.length) {
  25. if (builder.current.length === builder.offset) return builder.current.join('');
  26. return builder.current.splice(0, builder.offset).join('');
  27. }
  28. if (builder.offset > 0) {
  29. builder.chunks[builder.chunks.length] = builder.current.length === builder.offset
  30. ? builder.current.join('')
  31. : builder.current.slice(0, builder.offset).join('');
  32. }
  33. return builder.chunks.join('');
  34. }
  35. export function getSize(builder: StringBuilder): number {
  36. let size = 0;
  37. for (const c of builder.chunks) size += c.length;
  38. for (let i = 0; i < builder.offset; i++) size += builder.current[i].length;
  39. return size;
  40. }
  41. export function getChunks(builder: StringBuilder): string[] {
  42. if (builder.offset > 0) {
  43. if (builder.current.length === builder.offset) builder.chunks[builder.chunks.length] = builder.current.join('');
  44. else builder.chunks[builder.chunks.length] = builder.current.slice(0, builder.offset).join('');
  45. builder.offset = 0;
  46. }
  47. return builder.chunks;
  48. }
  49. const enum PaddingSpaces { Count = 512 }
  50. const __paddingSpaces: string[] = [];
  51. (function () {
  52. let s = '';
  53. for (let i = 0; i < PaddingSpaces.Count; i++) {
  54. __paddingSpaces[i] = s;
  55. s = s + ' ';
  56. }
  57. })();
  58. export function newline(builder: StringBuilder) {
  59. writeSafe(builder, '\n');
  60. }
  61. export function whitespace(builder: StringBuilder, len: number) {
  62. if (len > 0) writeSafe(builder, __paddingSpaces[len]);
  63. }
  64. export function whitespace1(builder: StringBuilder) {
  65. writeSafe(builder, ' ');
  66. }
  67. export function write(builder: StringBuilder, val: string) {
  68. if (!val) return;
  69. if (builder.offset === builder.capacity) {
  70. builder.chunks[builder.chunks.length] = builder.current.join('');
  71. builder.offset = 0;
  72. }
  73. builder.current[builder.offset++] = val;
  74. }
  75. /** Write without check. */
  76. export function writeSafe(builder: StringBuilder, val: string) {
  77. if (builder.offset === builder.capacity) {
  78. builder.chunks[builder.chunks.length] = builder.current.join('');
  79. builder.offset = 0;
  80. }
  81. builder.current[builder.offset++] = val;
  82. }
  83. export function writePadLeft(builder: StringBuilder, val: string, totalWidth: number) {
  84. if (!val) { whitespace(builder, totalWidth); return; }
  85. const padding = totalWidth - val.length;
  86. whitespace(builder, padding);
  87. writeSafe(builder, val);
  88. }
  89. export function writePadRight(builder: StringBuilder, val: string, totalWidth: number) {
  90. if (!val) { whitespace(builder, totalWidth); return; }
  91. const padding = totalWidth - val.length;
  92. writeSafe(builder, val);
  93. whitespace(builder, padding);
  94. }
  95. export function writeInteger(builder: StringBuilder, val: number) {
  96. writeSafe(builder, '' + val);
  97. }
  98. export function writeIntegerAndSpace(builder: StringBuilder, val: number) {
  99. writeSafe(builder, '' + val + ' ');
  100. }
  101. export function writeIntegerPadLeft(builder: StringBuilder, val: number, totalWidth: number) {
  102. const s = '' + val;
  103. const padding = totalWidth - s.length;
  104. whitespace(builder, padding);
  105. writeSafe(builder, s);
  106. }
  107. export function writeIntegerPadRight(builder: StringBuilder, val: number, totalWidth: number) {
  108. const s = '' + val;
  109. const padding = totalWidth - s.length;
  110. writeSafe(builder, s);
  111. whitespace(builder, padding);
  112. }
  113. /**
  114. * @example writeFloat(123.2123, 100) -- 2 decim
  115. */
  116. export function writeFloat(builder: StringBuilder, val: number, precisionMultiplier: number) {
  117. writeSafe(builder, '' + Math.round(precisionMultiplier * val) / precisionMultiplier);
  118. }
  119. export function writeFloatPadLeft(builder: StringBuilder, val: number, precisionMultiplier: number, totalWidth: number) {
  120. const s = '' + Math.round(precisionMultiplier * val) / precisionMultiplier;
  121. const padding = totalWidth - s.length;
  122. whitespace(builder, padding);
  123. writeSafe(builder, s);
  124. }
  125. export function writeFloatPadRight(builder: StringBuilder, val: number, precisionMultiplier: number, totalWidth: number) {
  126. const s = '' + Math.round(precisionMultiplier * val) / precisionMultiplier;
  127. const padding = totalWidth - s.length;
  128. writeSafe(builder, s);
  129. whitespace(builder, padding);
  130. }
  131. }
  132. export { StringBuilder };