Skip to content

Commit 088644c

Browse files
authored
Improve SourceMap coverage/testing (shader-slang#2818)
* #include an absolute path didn't work - because paths were taken to always be relative. * WIP around more value like behavior for SourceMap/StringPool. * Use default impls on SourceMap ctor/assignment. * Handle comparison of SourceMaps. Some small fixes. Expand unit tests.
1 parent 4e67cde commit 088644c

6 files changed

+305
-31
lines changed

source/compiler-core/slang-json-source-map-util.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ void _encode(Index v, StringBuilder& out)
209209
cur = StringSlicePool::kNullHandle;
210210
}
211211

212+
// Special case sourcesContent, because needs to be able to handle null or string
212213
for (Index i = 0; i < sourcesContentCount; ++i)
213214
{
214215
auto value = native.sourcesContent[i];
@@ -223,6 +224,17 @@ void _encode(Index v, StringBuilder& out)
223224
}
224225
}
225226

227+
// Copy over the names
228+
{
229+
const auto namesCount = native.names.getCount();
230+
outSourceMap.m_names.setCount(namesCount);
231+
232+
for (Index i = 0; i < namesCount; ++i)
233+
{
234+
outSourceMap.m_names[i] = outSourceMap.m_slicePool.add(native.names[i]);
235+
}
236+
}
237+
226238
List<UnownedStringSlice> lines;
227239
StringUtil::split(native.mappings, ';', lines);
228240

source/compiler-core/slang-source-map.cpp

+99
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,105 @@ void SourceMap::swapWith(ThisType& rhs)
3535
m_slicePool.swapWith(rhs.m_slicePool);
3636
}
3737

38+
static bool _areEqual(const List<StringSlicePool::Handle>& a, const List<StringSlicePool::Handle>& b, const List<Index>& bToAMap)
39+
{
40+
const auto count = a.getCount();
41+
if (count != b.getCount())
42+
{
43+
return false;
44+
}
45+
46+
const auto* as = a.getBuffer();
47+
const auto* bs = a.getBuffer();
48+
49+
for (Index i = 0; i < count; ++i)
50+
{
51+
if (StringSlicePool::asIndex(as[i]) != bToAMap[StringSlicePool::asIndex(bs[i])])
52+
{
53+
return false;
54+
}
55+
}
56+
57+
return true;
58+
}
59+
60+
static bool _areEqual(const SourceMap::Entry& a, const SourceMap::Entry& b, const List<Index>& bToAMap)
61+
{
62+
return a.generatedColumn == b.generatedColumn &&
63+
a.sourceLine == b.sourceLine &&
64+
a.sourceColumn == b.sourceColumn &&
65+
a.sourceFileIndex == bToAMap[b.sourceFileIndex] &&
66+
a.nameIndex == bToAMap[b.nameIndex];
67+
}
68+
69+
static bool _areEqual(const List<SourceMap::Entry>& a, const List<SourceMap::Entry>&b, const List<Index>& bToAMap)
70+
{
71+
const auto count = a.getCount();
72+
if (count != b.getCount())
73+
{
74+
return false;
75+
}
76+
77+
for (Index i = 0; i < count; ++i)
78+
{
79+
if (!_areEqual(a[i], b[i], bToAMap))
80+
{
81+
return false;
82+
}
83+
}
84+
85+
return true;
86+
}
87+
88+
bool SourceMap::operator==(const ThisType& rhs) const
89+
{
90+
if (this == &rhs)
91+
{
92+
return true;
93+
}
94+
95+
if (m_file != rhs.m_file ||
96+
m_sourceRoot != rhs.m_sourceRoot ||
97+
m_lineStarts != rhs.m_lineStarts)
98+
{
99+
return false;
100+
}
101+
102+
if (m_slicePool == rhs.m_slicePool)
103+
{
104+
// If the slice pools are the same we can just compare indices directly
105+
return m_sources == rhs.m_sources &&
106+
m_sourcesContent == rhs.m_sourcesContent &&
107+
m_names == rhs.m_names &&
108+
m_lineEntries == rhs.m_lineEntries;
109+
}
110+
else
111+
{
112+
// Otherwise we need to remap the indices
113+
// Maps a pool handle from the rhs source map to the
114+
List<Index> rhsMap;
115+
116+
Count count = rhs.m_slicePool.getSlicesCount();
117+
118+
rhsMap.setCount(count);
119+
120+
const auto startIndex = rhs.m_slicePool.getFirstAddedIndex();
121+
122+
// Work out the map
123+
for (Index i = 0; i < startIndex; ++i)
124+
{
125+
const auto rhsSlice = rhs.m_slicePool.getSlice(StringSlicePool::Handle(i));
126+
rhsMap[i] = (i < startIndex) ? i : m_slicePool.findIndex(rhsSlice);
127+
}
128+
129+
// Do the comparison taking into account the mapping.
130+
return _areEqual(m_sources, rhs.m_sources, rhsMap) &&
131+
_areEqual(m_sourcesContent, rhs.m_sourcesContent, rhsMap) &&
132+
_areEqual(m_names, rhs.m_names, rhsMap) &&
133+
_areEqual(m_lineEntries, rhs.m_lineEntries, rhsMap);
134+
}
135+
}
136+
38137
void SourceMap::advanceToLine(Index nextLineIndex)
39138
{
40139
const Count currentLineIndex = getGeneratedLineCount() - 1;

source/compiler-core/slang-source-map.h

+24
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class SourceMap
1919

2020
struct Entry
2121
{
22+
typedef Entry ThisType;
23+
2224
void init()
2325
{
2426
generatedColumn = 0;
@@ -28,6 +30,16 @@ class SourceMap
2830
nameIndex = 0;
2931
}
3032

33+
bool operator==(const ThisType& rhs) const
34+
{
35+
return generatedColumn == rhs.generatedColumn &&
36+
sourceFileIndex == rhs.sourceFileIndex &&
37+
sourceLine == rhs.sourceLine &&
38+
sourceColumn == rhs.sourceColumn &&
39+
nameIndex == rhs.nameIndex;
40+
}
41+
SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); }
42+
3143
// Note! All column/line are zero indexed
3244
Index generatedColumn; ///< The generated column
3345
Index sourceFileIndex; ///< The index into the source name/contents
@@ -71,12 +83,24 @@ class SourceMap
7183
/// Swap this with rhs
7284
void swapWith(ThisType& rhs);
7385

86+
/// ==
87+
///
88+
/// Note that equality requires that entries for a line must be *in the same order*
89+
/// even though strictly speaking with different orders could be considered equivalent.
90+
bool operator==(const ThisType& rhs) const;
91+
/// !=
92+
bool operator!=(const ThisType& rhs) const { return !(*this == rhs); }
93+
7494
/// Ctor
7595
SourceMap():
7696
m_slicePool(StringSlicePool::Style::Default)
7797
{
7898
clear();
7999
}
100+
/// Copy Ctor
101+
SourceMap(const ThisType& rhs) = default;
102+
/// Assignment
103+
ThisType& operator=(const ThisType& rhs) = default;
80104

81105
String m_file;
82106
String m_sourceRoot;

source/core/slang-string-slice-pool.cpp

+94
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,103 @@ StringSlicePool::StringSlicePool(Style style) :
1414
clear();
1515
}
1616

17+
StringSlicePool::StringSlicePool(const ThisType& rhs):
18+
m_style(rhs.m_style),
19+
m_arena(1024)
20+
{
21+
// Set with rhs
22+
_set(rhs);
23+
}
24+
25+
void StringSlicePool::operator=(const ThisType& rhs)
26+
{
27+
if (&rhs != this)
28+
{
29+
_set(rhs);
30+
}
31+
}
32+
33+
void StringSlicePool::_set(const ThisType& rhs)
34+
{
35+
SLANG_ASSERT(this != &rhs);
36+
m_style = rhs.m_style;
37+
38+
clear();
39+
40+
const Index startIndex = rhs.getFirstAddedIndex();
41+
const Count count = rhs.m_slices.getCount();
42+
43+
// We need the same amount of slices
44+
m_slices.setCount(count);
45+
46+
// Work out the total size to store all slices including terminating 0
47+
// (which *isn't* part of the slice size)
48+
size_t totalSize = 0;
49+
50+
for (Index i = startIndex; i < count; ++i)
51+
{
52+
const auto slice = rhs.m_slices[i];
53+
totalSize += slice.getLength() + 1;
54+
}
55+
56+
char* dst = (char*)m_arena.allocate(totalSize);
57+
58+
for (Index i = startIndex; i < count; ++i)
59+
{
60+
const auto srcSlice = rhs.m_slices[i];
61+
const auto sliceSize = srcSlice.getLength();
62+
63+
// Copy over the src slices contents
64+
::memcpy(dst, srcSlice.begin(), sliceSize);
65+
// Zero terminate
66+
dst[sliceSize] = 0;
67+
68+
const UnownedStringSlice dstSlice(dst, sliceSize);
69+
// Set the slice
70+
m_slices[i] = dstSlice;
71+
72+
// Add to the map
73+
m_map.Add(dstSlice, Handle(i));
74+
75+
// Skip to next slices storage
76+
dst += sliceSize + 1;
77+
}
78+
}
79+
80+
bool StringSlicePool::operator==(const ThisType& rhs) const
81+
{
82+
if (this == &rhs)
83+
{
84+
return true;
85+
}
86+
87+
if (m_style != rhs.m_style)
88+
{
89+
return false;
90+
}
91+
92+
const auto count = m_slices.getCount();
93+
94+
if (count != rhs.m_slices.getCount())
95+
{
96+
return false;
97+
}
98+
99+
for (Index i = 0; i < count; ++i)
100+
{
101+
if (m_slices[i] != rhs.m_slices[i])
102+
{
103+
return false;
104+
}
105+
}
106+
107+
return true;
108+
}
109+
17110
void StringSlicePool::clear()
18111
{
19112
m_map.Clear();
113+
m_arena.deallocateAll();
20114

21115
switch (m_style)
22116
{

source/core/slang-string-slice-pool.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,19 @@ class StringSlicePool
102102
/// Swap this with rhs
103103
void swapWith(ThisType& rhs);
104104

105+
/// True if the pools are identical. Same style, same slices in the same order.
106+
bool operator==(const ThisType& rhs) const;
107+
108+
/// Copy ctor
109+
StringSlicePool(const ThisType& rhs);
110+
/// Assignment
111+
void operator=(const ThisType& rhs);
112+
105113
/// Ctor
106114
explicit StringSlicePool(Style style);
107115

108116
protected:
109-
// Disable copy ctor and assignment
110-
StringSlicePool(const ThisType& rhs) = delete;
111-
void operator=(const ThisType& rhs) = delete;
117+
void _set(const ThisType& rhs);
112118

113119
Style m_style;
114120
List<UnownedStringSlice> m_slices;

0 commit comments

Comments
 (0)