| 101 | } |
| 102 | |
| 103 | Ref<CharacterSet> CharacterSet::make(const CharacterRange* ranges, size_t length) { |
| 104 | std::vector<CharacterRange> sortedRanges; |
| 105 | if (needsSort(ranges, length)) { |
| 106 | sortedRanges = std::vector<CharacterRange>(ranges, ranges + length); |
| 107 | std::sort(sortedRanges.begin(), sortedRanges.end(), [](const auto& left, const auto& right) { |
| 108 | return left.from < right.from; |
| 109 | }); |
| 110 | |
| 111 | ranges = sortedRanges.data(); |
| 112 | } |
| 113 | |
| 114 | std::optional<uint32_t> minOffsetIndex; |
| 115 | uint32_t lastOffsetIndex = 0; |
| 116 | uint32_t resolvedBitsetsCount = 0; |
| 117 | processCharacters(ranges, length, [&](uint32_t offsetIndex, uint32_t bitsetsCount, uint32_t /*offsetValue*/) { |
| 118 | if (!minOffsetIndex || minOffsetIndex.value() > offsetIndex) { |
| 119 | minOffsetIndex = {offsetIndex}; |
| 120 | } |
| 121 | resolvedBitsetsCount = bitsetsCount; |
| 122 | lastOffsetIndex = std::max(lastOffsetIndex, offsetIndex); |
| 123 | }); |
| 124 | |
| 125 | auto resolvedMinOffsetIndex = minOffsetIndex ? minOffsetIndex.value() : 0; |
| 126 | auto totalOffsetsCount = (lastOffsetIndex - resolvedMinOffsetIndex) + 1; |
| 127 | auto totalBitsetsCount = resolvedBitsetsCount + 1; |
| 128 | |
| 129 | auto offsetsAllocSize = totalOffsetsCount * sizeof(uint16_t); |
| 130 | auto bitsetsAllocSize = totalBitsetsCount * sizeof(Bitset); |
| 131 | |
| 132 | auto baseAllocSize = sizeof(CharacterSet); |
| 133 | auto withOffsetsAllocSize = Valdi::alignUp(baseAllocSize + offsetsAllocSize, alignof(uint16_t)); |
| 134 | auto withBitsetsAllocSize = Valdi::alignUp(withOffsetsAllocSize + bitsetsAllocSize, alignof(Bitset)); |
| 135 | |
| 136 | std::allocator<uint8_t> allocator; |
| 137 | auto* region = allocator.allocate(withBitsetsAllocSize); |
| 138 | std::memset(region, 0, withBitsetsAllocSize); |
| 139 | |
| 140 | auto* offsets = reinterpret_cast<uint16_t*>(®ion[withOffsetsAllocSize - offsetsAllocSize]); |
| 141 | auto* bitsets = reinterpret_cast<Bitset*>(®ion[withBitsetsAllocSize - bitsetsAllocSize]); |
| 142 | |
| 143 | initializeBitsets(ranges, length, resolvedMinOffsetIndex, offsets, bitsets); |
| 144 | |
| 145 | new (region)(CharacterSet)(resolvedMinOffsetIndex, lastOffsetIndex, offsets, bitsets); |
| 146 | |
| 147 | return Ref<CharacterSet>(reinterpret_cast<CharacterSet*>(region)); |
| 148 | } |
| 149 | |
| 150 | bool CharacterSet::operator==(const CharacterSet& other) const { |
| 151 | if (_minOffset != other._minOffset || _maxOffset != other._maxOffset) { |