1 /* 2 * Copyright (C) 2013, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "dictionary/structure/pt_common/dynamic_pt_writing_utils.h" 18 19 #include <cstddef> 20 #include <cstdint> 21 #include <cstdlib> 22 23 #include "dictionary/utils/buffer_with_extendable_buffer.h" 24 25 namespace latinime { 26 27 const size_t DynamicPtWritingUtils::MAX_PTNODE_ARRAY_SIZE_TO_USE_SMALL_SIZE_FIELD = 0x7F; 28 const size_t DynamicPtWritingUtils::MAX_PTNODE_ARRAY_SIZE = 0x7FFF; 29 const int DynamicPtWritingUtils::SMALL_PTNODE_ARRAY_SIZE_FIELD_SIZE = 1; 30 const int DynamicPtWritingUtils::LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE = 2; 31 const int DynamicPtWritingUtils::LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG = 0x8000; 32 const int DynamicPtWritingUtils::DICT_OFFSET_FIELD_SIZE = 3; 33 const int DynamicPtWritingUtils::MAX_DICT_OFFSET_VALUE = 0x7FFFFF; 34 const int DynamicPtWritingUtils::MIN_DICT_OFFSET_VALUE = -0x7FFFFF; 35 const int DynamicPtWritingUtils::DICT_OFFSET_NEGATIVE_FLAG = 0x800000; 36 const int DynamicPtWritingUtils::NODE_FLAG_FIELD_SIZE = 1; 37 38 /* static */ bool DynamicPtWritingUtils::writeEmptyDictionary( 39 BufferWithExtendableBuffer *const buffer, const int rootPos) { 40 int writingPos = rootPos; 41 if (!writePtNodeArraySizeAndAdvancePosition(buffer, 0 /* arraySize */, &writingPos)) { 42 return false; 43 } 44 return writeForwardLinkPositionAndAdvancePosition(buffer, NOT_A_DICT_POS /* forwardLinkPos */, 45 &writingPos); 46 } 47 48 /* static */ bool DynamicPtWritingUtils::writeForwardLinkPositionAndAdvancePosition( 49 BufferWithExtendableBuffer *const buffer, const int forwardLinkPos, 50 int *const forwardLinkFieldPos) { 51 return writeDictOffset(buffer, forwardLinkPos, (*forwardLinkFieldPos), forwardLinkFieldPos); 52 } 53 54 /* static */ bool DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition( 55 BufferWithExtendableBuffer *const buffer, const size_t arraySize, 56 int *const arraySizeFieldPos) { 57 // Currently, all array size field to be created has LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE to 58 // simplify updating process. 59 // TODO: Use SMALL_PTNODE_ARRAY_SIZE_FIELD_SIZE for small arrays. 60 /*if (arraySize <= MAX_PTNODE_ARRAY_SIZE_TO_USE_SMALL_SIZE_FIELD) { 61 return buffer->writeUintAndAdvancePosition(arraySize, SMALL_PTNODE_ARRAY_SIZE_FIELD_SIZE, 62 arraySizeFieldPos); 63 } else */ 64 if (arraySize <= MAX_PTNODE_ARRAY_SIZE) { 65 uint32_t data = arraySize | LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG; 66 return buffer->writeUintAndAdvancePosition(data, LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE, 67 arraySizeFieldPos); 68 } else { 69 AKLOGI("PtNode array size cannot be written because arraySize is too large: %zd", 70 arraySize); 71 ASSERT(false); 72 return false; 73 } 74 } 75 76 /* static */ bool DynamicPtWritingUtils::writeFlagsAndAdvancePosition( 77 BufferWithExtendableBuffer *const buffer, 78 const DynamicPtReadingUtils::NodeFlags nodeFlags, int *const nodeFlagsFieldPos) { 79 return buffer->writeUintAndAdvancePosition(nodeFlags, NODE_FLAG_FIELD_SIZE, nodeFlagsFieldPos); 80 } 81 82 // Note that parentOffset is offset from node's head position. 83 /* static */ bool DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition( 84 BufferWithExtendableBuffer *const buffer, const int parentPos, const int basePos, 85 int *const parentPosFieldPos) { 86 return writeDictOffset(buffer, parentPos, basePos, parentPosFieldPos); 87 } 88 89 /* static */ bool DynamicPtWritingUtils::writeCodePointsAndAdvancePosition( 90 BufferWithExtendableBuffer *const buffer, const int *const codePoints, 91 const int codePointCount, int *const codePointFieldPos) { 92 if (codePointCount <= 0) { 93 AKLOGI("code points cannot be written because codePointCount is invalid: %d", 94 codePointCount); 95 ASSERT(false); 96 return false; 97 } 98 const bool hasMultipleCodePoints = codePointCount > 1; 99 return buffer->writeCodePointsAndAdvancePosition(codePoints, codePointCount, 100 hasMultipleCodePoints, codePointFieldPos); 101 } 102 103 /* static */ bool DynamicPtWritingUtils::writeChildrenPositionAndAdvancePosition( 104 BufferWithExtendableBuffer *const buffer, const int childrenPosition, 105 int *const childrenPositionFieldPos) { 106 return writeDictOffset(buffer, childrenPosition, (*childrenPositionFieldPos), 107 childrenPositionFieldPos); 108 } 109 110 /* static */ bool DynamicPtWritingUtils::writeDictOffset(BufferWithExtendableBuffer *const buffer, 111 const int targetPos, const int basePos, int *const offsetFieldPos) { 112 int offset = targetPos - basePos; 113 if (targetPos == NOT_A_DICT_POS) { 114 offset = DynamicPtReadingUtils::DICT_OFFSET_INVALID; 115 } else if (offset == 0) { 116 offset = DynamicPtReadingUtils::DICT_OFFSET_ZERO_OFFSET; 117 } 118 if (offset > MAX_DICT_OFFSET_VALUE || offset < MIN_DICT_OFFSET_VALUE) { 119 AKLOGI("offset cannot be written because the offset is too large or too small: %d", 120 offset); 121 ASSERT(false); 122 return false; 123 } 124 uint32_t data = 0; 125 if (offset >= 0) { 126 data = offset; 127 } else { 128 data = abs(offset) | DICT_OFFSET_NEGATIVE_FLAG; 129 } 130 return buffer->writeUintAndAdvancePosition(data, DICT_OFFSET_FIELD_SIZE, offsetFieldPos); 131 } 132 } 133