| 27 | } |
| 28 | |
| 29 | fl::string StringInterner::intern(const string_view& sv) { |
| 30 | if (sv.empty()) return fl::string(); |
| 31 | |
| 32 | // SSO optimization: strings that fit in the inline buffer don't benefit from interning |
| 33 | // because fl::string will store them inline (no heap allocation anyway). |
| 34 | // Interning small strings would just add hash overhead with no memory savings. |
| 35 | if (sv.size() <= FASTLED_STR_INLINED_SIZE) { |
| 36 | return fl::string(sv); |
| 37 | } |
| 38 | |
| 39 | // String is large enough to require heap allocation - check if already interned |
| 40 | // Try to find existing entry - O(1) average via hash map |
| 41 | auto it = mEntries.find(sv); |
| 42 | if (it != mEntries.end()) { |
| 43 | // Found existing - return fl::string sharing the StringHolder |
| 44 | return fl::string(it->second); |
| 45 | } |
| 46 | |
| 47 | // Not found - create new StringHolder (heap-allocated) |
| 48 | auto holder = fl::make_shared<StringHolder>(sv.data(), sv.size()); |
| 49 | |
| 50 | // Create string_view key that points into holder's data |
| 51 | // This is safe because StringHolder data is heap-allocated and never moves |
| 52 | string_view key(holder->data(), holder->length()); |
| 53 | |
| 54 | // Insert into map - key points into value's data (self-referential) |
| 55 | mEntries[key] = holder; |
| 56 | |
| 57 | // Return fl::string sharing the StringHolder |
| 58 | return fl::string(holder); |
| 59 | } |
| 60 | |
| 61 | fl::string StringInterner::intern(const fl::string& str) { |
| 62 | // Convert to string_view and delegate |
no test coverage detected