writeable_node.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #include "writeable_node.h"
  2. #include "node.h"
  3. #include "comptrie_impl.h"
  4. namespace NCompactTrie {
  5. TWriteableNode::TWriteableNode()
  6. : LeafPos(nullptr)
  7. , LeafLength(0)
  8. , ForwardOffset(NPOS)
  9. , LeftOffset(NPOS)
  10. , RightOffset(NPOS)
  11. , Label(0)
  12. {
  13. }
  14. static size_t GetOffsetFromEnd(const TNode& node, size_t absOffset) {
  15. return absOffset ? absOffset - node.GetOffset() - node.GetCoreLength() : NPOS;
  16. }
  17. TWriteableNode::TWriteableNode(const TNode& node, const char* data)
  18. : LeafPos(node.IsFinal() ? data + node.GetLeafOffset() : nullptr)
  19. , LeafLength(node.GetLeafLength())
  20. , ForwardOffset(GetOffsetFromEnd(node, node.GetForwardOffset()))
  21. , LeftOffset(GetOffsetFromEnd(node, node.GetLeftOffset()))
  22. , RightOffset(GetOffsetFromEnd(node, node.GetRightOffset()))
  23. , Label(node.GetLabel())
  24. {
  25. }
  26. size_t TWriteableNode::Measure() const {
  27. size_t len = 2 + LeafLength;
  28. size_t fwdLen = 0;
  29. size_t lastLen = 0;
  30. size_t lastFwdLen = 0;
  31. // Now, increase all the offsets by the length and recalculate everything, until it converges
  32. do {
  33. lastLen = len;
  34. lastFwdLen = fwdLen;
  35. len = 2 + LeafLength;
  36. len += MeasureOffset(LeftOffset != NPOS ? LeftOffset + lastLen : 0);
  37. len += MeasureOffset(RightOffset != NPOS ? RightOffset + lastLen : 0);
  38. // Relative forward offset of 0 means we don't need extra length for an epsilon link.
  39. // But an epsilon link means we need an extra 1 for the flags and the forward offset is measured
  40. // from the start of the epsilon link, not from the start of our node.
  41. if (ForwardOffset != NPOS && ForwardOffset != 0) {
  42. fwdLen = MeasureOffset(ForwardOffset + lastFwdLen) + 1;
  43. len += fwdLen;
  44. }
  45. } while (lastLen != len || lastFwdLen != fwdLen);
  46. return len;
  47. }
  48. size_t TWriteableNode::Pack(char* buffer) const {
  49. const size_t length = Measure();
  50. char flags = 0;
  51. if (LeafPos) {
  52. flags |= MT_FINAL;
  53. }
  54. if (ForwardOffset != NPOS) {
  55. flags |= MT_NEXT;
  56. }
  57. const size_t leftOffset = LeftOffset != NPOS ? LeftOffset + length : 0;
  58. const size_t rightOffset = RightOffset != NPOS ? RightOffset + length : 0;
  59. const size_t leftOffsetSize = MeasureOffset(leftOffset);
  60. const size_t rightOffsetSize = MeasureOffset(rightOffset);
  61. flags |= (leftOffsetSize << MT_LEFTSHIFT);
  62. flags |= (rightOffsetSize << MT_RIGHTSHIFT);
  63. buffer[0] = flags;
  64. buffer[1] = Label;
  65. size_t usedLen = 2;
  66. usedLen += PackOffset(buffer + usedLen, leftOffset);
  67. usedLen += PackOffset(buffer + usedLen, rightOffset);
  68. if (LeafPos && LeafLength) {
  69. memcpy(buffer + usedLen, LeafPos, LeafLength);
  70. usedLen += LeafLength;
  71. }
  72. if (ForwardOffset != NPOS && ForwardOffset != 0) {
  73. const size_t fwdOffset = ForwardOffset + length - usedLen;
  74. size_t fwdOffsetSize = MeasureOffset(fwdOffset);
  75. buffer[usedLen++] = (char)(fwdOffsetSize & MT_SIZEMASK);
  76. usedLen += PackOffset(buffer + usedLen, fwdOffset);
  77. }
  78. Y_ASSERT(usedLen == length);
  79. return usedLen;
  80. }
  81. }