Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:10

0001 //===- StringTable.h - Table of strings tracked by offset ----------C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLVM_ADT_STRING_TABLE_H
0010 #define LLVM_ADT_STRING_TABLE_H
0011 
0012 #include "llvm/ADT/StringRef.h"
0013 #include "llvm/ADT/iterator.h"
0014 #include <iterator>
0015 #include <limits>
0016 
0017 namespace llvm {
0018 
0019 /// A table of densely packed, null-terminated strings indexed by offset.
0020 ///
0021 /// This table abstracts a densely concatenated list of null-terminated strings,
0022 /// each of which can be referenced using an offset into the table.
0023 ///
0024 /// This requires and ensures that the string at offset 0 is also the empty
0025 /// string. This helps allow zero-initialized offsets form empty strings and
0026 /// avoids non-zero initialization when using a string literal pointer would
0027 /// allow a null pointer.
0028 ///
0029 /// The primary use case is having a single global string literal for the table
0030 /// contents, and offsets into it in other global data structures to avoid
0031 /// dynamic relocations of individual string literal pointers in those global
0032 /// data structures.
0033 class StringTable {
0034   StringRef Table;
0035 
0036 public:
0037   // An offset into one of these packed string tables, used to select a string
0038   // within the table.
0039   //
0040   // Typically these are created by TableGen or other code generator from
0041   // computed offsets, and it just wraps that integer into a type until it is
0042   // used with the relevant table.
0043   //
0044   // We also ensure that the empty string is at offset zero and default
0045   // constructing this class gives you an offset of zero. This makes default
0046   // constructing this type work similarly (after indexing the table) to default
0047   // constructing a `StringRef`.
0048   class Offset {
0049     // Note that we ensure the empty string is at offset zero.
0050     unsigned Value = 0;
0051 
0052   public:
0053     constexpr Offset() = default;
0054     constexpr Offset(unsigned Value) : Value(Value) {}
0055 
0056     friend constexpr bool operator==(const Offset &LHS, const Offset &RHS) {
0057       return LHS.Value == RHS.Value;
0058     }
0059 
0060     friend constexpr bool operator!=(const Offset &LHS, const Offset &RHS) {
0061       return LHS.Value != RHS.Value;
0062     }
0063 
0064     constexpr unsigned value() const { return Value; }
0065   };
0066 
0067   // We directly handle string literals with a templated converting constructor
0068   // because we *don't* want to do `strlen` on them -- we fully expect null
0069   // bytes in this input. This is somewhat the opposite of how `StringLiteral`
0070   // works.
0071   template <size_t N>
0072   constexpr StringTable(const char (&RawTable)[N]) : Table(RawTable, N) {
0073     static_assert(N <= std::numeric_limits<unsigned>::max(),
0074                   "We only support table sizes that can be indexed by an "
0075                   "`unsigned` offset.");
0076 
0077     // Note that we can only use `empty`, `data`, and `size` in these asserts to
0078     // support `constexpr`.
0079     assert(!Table.empty() && "Requires at least a valid empty string.");
0080     assert(Table.data()[0] == '\0' && "Offset zero must be the empty string.");
0081     // Regardless of how many strings are in the table, the last one should also
0082     // be null terminated. This also ensures that computing `strlen` on the
0083     // strings can't accidentally run past the end of the table.
0084     assert(Table.data()[Table.size() - 1] == '\0' &&
0085            "Last byte must be a null byte.");
0086   }
0087 
0088   // Get a string from the table starting with the provided offset. The returned
0089   // `StringRef` is in fact null terminated, and so can be converted safely to a
0090   // C-string if necessary for a system API.
0091   constexpr StringRef operator[](Offset O) const {
0092     assert(O.value() < Table.size() && "Out of bounds offset!");
0093     return Table.data() + O.value();
0094   }
0095 
0096   /// Returns the byte size of the table.
0097   constexpr size_t size() const { return Table.size(); }
0098 
0099   class Iterator
0100       : public iterator_facade_base<Iterator, std::forward_iterator_tag,
0101                                     const StringRef> {
0102     friend StringTable;
0103 
0104     const StringTable *Table;
0105     Offset O;
0106 
0107     // A cache of one value to allow `*` to return a reference.
0108     mutable StringRef S;
0109 
0110     explicit constexpr Iterator(const StringTable &Table, Offset O)
0111         : Table(&Table), O(O) {}
0112 
0113   public:
0114     constexpr Iterator(const Iterator &RHS) = default;
0115     constexpr Iterator(Iterator &&RHS) = default;
0116 
0117     bool operator==(const Iterator &RHS) const {
0118       assert(Table == RHS.Table && "Compared iterators for unrelated tables!");
0119       return O == RHS.O;
0120     }
0121 
0122     const StringRef &operator*() const {
0123       S = (*Table)[O];
0124       return S;
0125     }
0126 
0127     Iterator &operator++() {
0128       O = O.value() + (*Table)[O].size() + 1;
0129       return *this;
0130     }
0131   };
0132 
0133   constexpr Iterator begin() const { return Iterator(*this, 0); }
0134   constexpr Iterator end() const { return Iterator(*this, size() - 1); }
0135 };
0136 
0137 } // namespace llvm
0138 
0139 #endif // LLVM_ADT_STRING_TABLE_H