#include "slang-string-slice-pool.h" namespace Slang { /* static */ const StringSlicePool::Handle StringSlicePool::kNullHandle; /* static */ const StringSlicePool::Handle StringSlicePool::kEmptyHandle; /* static */ const Index StringSlicePool::kDefaultHandlesCount; StringSlicePool::StringSlicePool(Style style) : m_style(style), m_arena(1024) { clear(); } StringSlicePool::StringSlicePool(const ThisType& rhs) : m_style(rhs.m_style), m_arena(1024) { // Set with rhs _set(rhs); } void StringSlicePool::operator=(const ThisType& rhs) { if (&rhs != this) { _set(rhs); } } void StringSlicePool::_set(const ThisType& rhs) { SLANG_ASSERT(this != &rhs); m_style = rhs.m_style; clear(); const Index startIndex = rhs.getFirstAddedIndex(); const Count count = rhs.m_slices.getCount(); if (count == 0) return; // We need the same amount of slices m_slices.setCount(count); // Work out the total size to store all slices including terminating 0 // (which *isn't* part of the slice size) size_t totalSize = 0; for (Index i = startIndex; i < count; ++i) { const auto slice = rhs.m_slices[i]; totalSize += slice.getLength() + 1; } char* dst = (char*)m_arena.allocate(totalSize); for (Index i = startIndex; i < count; ++i) { const auto srcSlice = rhs.m_slices[i]; const auto sliceSize = srcSlice.getLength(); // Copy over the src slices contents ::memcpy(dst, srcSlice.begin(), sliceSize); // Zero terminate dst[sliceSize] = 0; const UnownedStringSlice dstSlice(dst, sliceSize); // Set the slice m_slices[i] = dstSlice; // Add to the map m_map.add(dstSlice, Handle(i)); // Skip to next slices storage dst += sliceSize + 1; } } bool StringSlicePool::operator==(const ThisType& rhs) const { if (this == &rhs) { return true; } if (m_style != rhs.m_style) { return false; } const auto count = m_slices.getCount(); if (count != rhs.m_slices.getCount()) { return false; } for (Index i = 0; i < count; ++i) { if (m_slices[i] != rhs.m_slices[i]) { return false; } } return true; } void StringSlicePool::clear() { m_map.clear(); m_arena.deallocateAll(); switch (m_style) { case Style::Default: { // Add the defaults m_slices.setCount(2); m_slices[0] = UnownedStringSlice((const char*)nullptr, (const char*)nullptr); m_slices[1] = UnownedStringSlice::fromLiteral(""); // Add the empty entry m_map.add(m_slices[1], kEmptyHandle); break; } case Style::Empty: { // There are no defaults m_slices.clear(); break; } } } void StringSlicePool::swapWith(ThisType& rhs) { Swap(m_style, rhs.m_style); m_slices.swapWith(rhs.m_slices); m_map.swapWith(rhs.m_map); m_arena.swapWith(rhs.m_arena); } StringSlicePool::Handle StringSlicePool::add(const Slice& slice) { const Handle* handlePtr = m_map.tryGetValue(slice); if (handlePtr) { return *handlePtr; } // Create a scoped copy UnownedStringSlice scopePath( m_arena.allocateString(slice.begin(), slice.getLength()), slice.getLength()); const auto index = m_slices.getCount(); m_slices.add(scopePath); m_map.add(scopePath, Handle(index)); return Handle(index); } bool StringSlicePool::findOrAdd(const Slice& slice, Handle& outHandle) { const Handle* handlePtr = m_map.tryGetValue(slice); if (handlePtr) { outHandle = *handlePtr; return true; } // Need to add. // Make a copy stored in the arena UnownedStringSlice scopeSlice( m_arena.allocateString(slice.begin(), slice.getLength()), slice.getLength()); // Add using the arenas copy Handle newHandle = Handle(m_slices.getCount()); m_map.add(scopeSlice, newHandle); // Add to slices list m_slices.add(scopeSlice); outHandle = newHandle; return false; } StringSlicePool::Handle StringSlicePool::add(StringRepresentation* stringRep) { if (stringRep == nullptr && m_style == Style::Default) { return kNullHandle; } return add(StringRepresentation::asSlice(stringRep)); } StringSlicePool::Handle StringSlicePool::add(const char* chars) { switch (m_style) { case Style::Default: { if (!chars) { return kNullHandle; } if (chars[0] == 0) { return kEmptyHandle; } break; } case Style::Empty: { if (chars == nullptr) { SLANG_ASSERT(!"Empty style doesn't support nullptr"); // Return an invalid handle return Handle(~HandleIntegral(0)); } } } return add(UnownedStringSlice(chars)); } Index StringSlicePool::findIndex(const Slice& slice) const { const Handle* handlePtr = m_map.tryGetValue(slice); return handlePtr ? Index(*handlePtr) : -1; } ConstArrayView StringSlicePool::getAdded() const { const Index firstIndex = getFirstAddedIndex(); return makeConstArrayView(m_slices.getBuffer() + firstIndex, m_slices.getCount() - firstIndex); } } // namespace Slang