WinCOFFObjectWriter: optimize the string table for common suffices

This is a follow-up from r207670 which did the same for ELF.

Differential Revision: http://reviews.llvm.org/D5530

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218636 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Hans Wennborg 2014-09-29 22:43:20 +00:00
parent 6a2169eb6f
commit 4edcbaec90
7 changed files with 121 additions and 107 deletions

View File

@ -29,9 +29,14 @@ public:
return StringIndexMap.GetOrCreateValue(s, 0).getKey();
}
enum Kind {
ELF,
WinCOFF
};
/// \brief Analyze the strings and build the final table. No more strings can
/// be added after this point.
void finalize();
void finalize(Kind kind);
/// \brief Retrieve the string table data. Can only be used after the table
/// is finalized.
@ -48,6 +53,8 @@ public:
return StringIndexMap[s];
}
void clear();
private:
bool isFinalized() {
return !StringTable.empty();

View File

@ -1073,7 +1073,7 @@ ELFObjectWriter::computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout,
for (auto i = Asm.file_names_begin(), e = Asm.file_names_end(); i != e; ++i)
StrTabBuilder.add(*i);
StrTabBuilder.finalize();
StrTabBuilder.finalize(StringTableBuilder::ELF);
for (auto i = Asm.file_names_begin(), e = Asm.file_names_end(); i != e; ++i)
FileSymbolData.push_back(StrTabBuilder.getOffset(*i));
@ -1446,7 +1446,7 @@ void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm,
static_cast<const MCSectionELF&>(it->getSection());
ShStrTabBuilder.add(Section.getSectionName());
}
ShStrTabBuilder.finalize();
ShStrTabBuilder.finalize(StringTableBuilder::ELF);
F->getContents().append(ShStrTabBuilder.data().begin(),
ShStrTabBuilder.data().end());
}

View File

@ -9,6 +9,8 @@
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
@ -25,19 +27,28 @@ static bool compareBySuffix(StringRef a, StringRef b) {
return sizeA > sizeB;
}
void StringTableBuilder::finalize() {
void StringTableBuilder::finalize(Kind kind) {
SmallVector<StringRef, 8> Strings;
Strings.reserve(StringIndexMap.size());
for (auto i = StringIndexMap.begin(), e = StringIndexMap.end(); i != e; ++i)
Strings.push_back(i->getKey());
std::sort(Strings.begin(), Strings.end(), compareBySuffix);
// FIXME: Starting with a null byte is ELF specific. Generalize this so we
// can use the class with other object formats.
StringTable += '\x00';
if (kind == ELF) {
// Start the table with a NUL byte.
StringTable += '\x00';
} else if (kind == WinCOFF) {
// Make room to write the table size later.
StringTable.append(4, '\x00');
}
StringRef Previous;
for (StringRef s : Strings) {
if (kind == WinCOFF)
assert(s.size() > COFF::NameSize && "Short string in COFF string table!");
if (Previous.endswith(s)) {
StringIndexMap[s] = StringTable.size() - 1 - s.size();
continue;
@ -48,4 +59,16 @@ void StringTableBuilder::finalize() {
StringTable += '\x00';
Previous = s;
}
if (kind == WinCOFF) {
assert(StringTable.size() <= std::numeric_limits<uint32_t>::max());
uint32_t size = static_cast<uint32_t>(StringTable.size());
support::endian::write<uint32_t, support::little, support::unaligned>(
StringTable.data(), size);
}
}
void StringTableBuilder::clear() {
StringTable.clear();
StringIndexMap.clear();
}

View File

@ -26,6 +26,7 @@
#include "llvm/MC/MCSectionCOFF.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
@ -102,25 +103,6 @@ public:
static size_t size();
};
// This class holds the COFF string table.
class StringTable {
typedef StringMap<size_t> map;
map Map;
void update_length();
public:
std::vector<char> Data;
StringTable();
size_t size() const;
size_t insert(StringRef String);
void clear() {
Map.clear();
Data.resize(4);
update_length();
}
};
class WinCOFFObjectWriter : public MCObjectWriter {
public:
@ -136,7 +118,7 @@ public:
COFF::header Header;
sections Sections;
symbols Symbols;
StringTable Strings;
StringTableBuilder Strings;
// Maps used during object file creation.
section_map SectionMap;
@ -168,8 +150,8 @@ public:
void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler,
const MCAsmLayout &Layout);
void MakeSymbolReal(COFFSymbol &S, size_t Index);
void MakeSectionReal(COFFSection &S, size_t Number);
void SetSymbolName(COFFSymbol &S);
void SetSectionName(COFFSection &S);
bool ExportSymbol(const MCSymbol &Symbol, MCAssembler &Asm);
@ -264,49 +246,6 @@ size_t COFFSection::size() {
return COFF::SectionSize;
}
//------------------------------------------------------------------------------
// StringTable class implementation
/// Write the length of the string table into Data.
/// The length of the string table includes uint32 length header.
void StringTable::update_length() {
write_uint32_le(&Data.front(), Data.size());
}
StringTable::StringTable() {
// The string table data begins with the length of the entire string table
// including the length header. Allocate space for this header.
Data.resize(4);
update_length();
}
size_t StringTable::size() const {
return Data.size();
}
/// Add String to the table iff it is not already there.
/// @returns the index into the string table where the string is now located.
size_t StringTable::insert(StringRef String) {
map::iterator i = Map.find(String);
if (i != Map.end())
return i->second;
size_t Offset = Data.size();
// Insert string data into string table.
Data.insert(Data.end(), String.begin(), String.end());
Data.push_back('\0');
// Put a reference to it in the map.
Map[String] = Offset;
// Update the internal length field.
update_length();
return Offset;
}
//------------------------------------------------------------------------------
// WinCOFFObjectWriter class implementation
@ -521,11 +460,9 @@ static void encodeBase64StringEntry(char* Buffer, uint64_t Value) {
}
}
/// making a section real involves assigned it a number and putting
/// name into the string table if needed
void WinCOFFObjectWriter::MakeSectionReal(COFFSection &S, size_t Number) {
void WinCOFFObjectWriter::SetSectionName(COFFSection &S) {
if (S.Name.size() > COFF::NameSize) {
uint64_t StringTableEntry = Strings.insert(S.Name.c_str());
uint64_t StringTableEntry = Strings.getOffset(S.Name);
if (StringTableEntry <= Max6DecimalOffset) {
std::sprintf(S.Header.Name, "/%d", unsigned(StringTableEntry));
@ -543,20 +480,13 @@ void WinCOFFObjectWriter::MakeSectionReal(COFFSection &S, size_t Number) {
}
} else
std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size());
S.Number = Number;
S.Symbol->Data.SectionNumber = S.Number;
S.Symbol->Aux[0].Aux.SectionDefinition.Number = S.Number;
}
void WinCOFFObjectWriter::MakeSymbolReal(COFFSymbol &S, size_t Index) {
if (S.Name.size() > COFF::NameSize) {
size_t StringTableEntry = Strings.insert(S.Name.c_str());
S.set_name_offset(StringTableEntry);
} else
void WinCOFFObjectWriter::SetSymbolName(COFFSymbol &S) {
if (S.Name.size() > COFF::NameSize)
S.set_name_offset(Strings.getOffset(S.Name));
else
std::memcpy(S.Data.Name, S.Name.c_str(), S.Name.size());
S.Index = Index;
}
bool WinCOFFObjectWriter::ExportSymbol(const MCSymbol &Symbol,
@ -860,10 +790,14 @@ void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm,
DenseMap<COFFSection *, int32_t> SectionIndices(
NextPowerOf2(NumberOfSections));
// Assign section numbers.
size_t Number = 1;
for (const auto &Section : Sections) {
SectionIndices[Section.get()] = Number;
MakeSectionReal(*Section, Number);
Section->Number = Number;
Section->Symbol->Data.SectionNumber = Number;
Section->Symbol->Aux[0].Aux.SectionDefinition.Number = Number;
++Number;
}
@ -903,10 +837,8 @@ void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm,
// Update section number & offset for symbols that have them.
if (Symbol->Section)
Symbol->Data.SectionNumber = Symbol->Section->Number;
if (Symbol->should_keep()) {
MakeSymbolReal(*Symbol, Header.NumberOfSymbols++);
Symbol->Index = Header.NumberOfSymbols++;
// Update auxiliary symbol info.
Symbol->Data.NumberOfAuxSymbols = Symbol->Aux.size();
Header.NumberOfSymbols += Symbol->Data.NumberOfAuxSymbols;
@ -914,6 +846,22 @@ void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm,
Symbol->Index = -1;
}
// Build string table.
for (const auto &S : Sections)
if (S->Name.size() > COFF::NameSize)
Strings.add(S->Name);
for (const auto &S : Symbols)
if (S->should_keep() && S->Name.size() > COFF::NameSize)
Strings.add(S->Name);
Strings.finalize(StringTableBuilder::WinCOFF);
// Set names.
for (const auto &S : Sections)
SetSectionName(*S);
for (auto &S : Symbols)
if (S->should_keep())
SetSymbolName(*S);
// Fixup weak external references.
for (auto & Symbol : Symbols) {
if (Symbol->Other) {
@ -1076,7 +1024,7 @@ void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm,
if (Symbol->Index != -1)
WriteSymbol(*Symbol);
OS.write((char const *)&Strings.Data.front(), Strings.Data.size());
OS.write(Strings.data().data(), Strings.data().size());
}
MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_) :

View File

@ -21,14 +21,19 @@
.section s1234567; .long 1
// Note: the names in the string table will be sorted in reverse
// lexicographical order. Use a suffix letter (z, y, x, ...) to
// get the preferred ordering of names in the test.
// Base 10 encoding
// Ending in z should put the name first in the string table.
// /4
// CHECK: Section {
// CHECK: Number: 6
// CHECK: Name: s12345678 (2F 34 00 00 00 00 00 00)
// CHECK: Name: s1234567z (2F 34 00 00 00 00 00 00)
// CHECK: }
.section s12345678; .long 1
.section s1234567z; .long 1
// Generate padding sections to increase the string table size to at least
@ -47,20 +52,20 @@
pad_sections2 \pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad\pad
.endm
// 1000x 'a'
pad_sections aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// 1000x 'y'
pad_sections yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
// /1000029 == 4 + 10 + (5 * (2 + (20 * 10 * 1000) + 1))
// v | | v ~~~~~~~~~~~~~~ v
// table size v v "p0" pad NUL separator
// "s12345678\0" # of pad sections
// "s1234567z\0" # of pad sections
//
// CHECK: Section {
// CHECK: Number: 12
// CHECK: Name: seven_digit (2F 31 30 30 30 30 32 39)
// CHECK: Name: sevendigitx (2F 31 30 30 30 30 32 39)
// CHECK: }
.section seven_digit; .long 1
.section sevendigitx; .long 1
// Generate padding sections to increase the string table size to at least
@ -71,18 +76,18 @@ pad_sections aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
.endm
// 1000x 'a'
pad_sections_ex aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
pad_sections_ex wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
// //AAmJa4 == 1000029 + 12 + (5 * (2 + (9 * 20 * 10 * 1000) + 1)) == 38*64^3 + 9*64^2 + 26*64 + 56
// v | | v ~~~~~~~~~~~~~~~~~~ v
// seven_digit offset v v "p0" pad NUL separator
// "seven_digit\0" # of pad sections
// "sevendigitx\0" # of pad sections
//
// "2F 2F 41 41 6D 4A 61 34" is "//AAmJa4", which decodes to "0 0 38 9 26 56".
//
// CHECK: Section {
// CHECK: Number: 18
// CHECK: Name: double_slash (2F 2F 41 41 6D 4A 61 34)
// CHECK: Name: doubleslashv (2F 2F 41 41 6D 4A 61 34)
// CHECK: }
.section double_slash; .long 1
.section doubleslashv; .long 1

View File

@ -190,7 +190,7 @@ bool ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
for (const auto &Sec : Doc.Sections)
DotShStrtab.add(Sec->Name);
DotShStrtab.finalize();
DotShStrtab.finalize(StringTableBuilder::ELF);
for (const auto &Sec : Doc.Sections) {
zero(SHeader);
@ -261,7 +261,7 @@ void ELFState<ELFT>::initSymtabSectionHeader(Elf_Shdr &SHeader,
DotStrtab.add(Sym.Name);
for (const auto &Sym : Doc.Symbols.Weak)
DotStrtab.add(Sym.Name);
DotStrtab.finalize();
DotStrtab.finalize(StringTableBuilder::ELF);
addSymbols(Doc.Symbols.Local, Syms, ELF::STB_LOCAL);
addSymbols(Doc.Symbols.Global, Syms, ELF::STB_GLOBAL);

View File

@ -9,20 +9,21 @@
#include "llvm/MC/StringTableBuilder.h"
#include "gtest/gtest.h"
#include "llvm/Support/Endian.h"
#include <string>
using namespace llvm;
namespace {
TEST(StringTableBuilderTest, Basic) {
TEST(StringTableBuilderTest, BasicELF) {
StringTableBuilder B;
B.add("foo");
B.add("bar");
B.add("foobar");
B.finalize();
B.finalize(StringTableBuilder::ELF);
std::string Expected;
Expected += '\x00';
@ -37,4 +38,34 @@ TEST(StringTableBuilderTest, Basic) {
EXPECT_EQ(8U, B.getOffset("foo"));
}
TEST(StringTableBuilderTest, BasicWinCOFF) {
StringTableBuilder B;
// Strings must be 9 chars or longer to go in the table.
B.add("hippopotamus");
B.add("pygmy hippopotamus");
B.add("river horse");
B.finalize(StringTableBuilder::WinCOFF);
// size_field + "pygmy hippopotamus\0" + "river horse\0"
uint32_t ExpectedSize = 4 + 19 + 12;
EXPECT_EQ(ExpectedSize, B.data().size());
std::string Expected;
ExpectedSize =
support::endian::byte_swap<uint32_t, support::little>(ExpectedSize);
Expected.append((const char*)&ExpectedSize, 4);
Expected += "pygmy hippopotamus";
Expected += '\x00';
Expected += "river horse";
Expected += '\x00';
EXPECT_EQ(Expected, B.data());
EXPECT_EQ(4U, B.getOffset("pygmy hippopotamus"));
EXPECT_EQ(10U, B.getOffset("hippopotamus"));
EXPECT_EQ(23U, B.getOffset("river horse"));
}
}