Skip to content

Commit a86d542

Browse files
committed
Fix code review feedback. Add tests for ContextCache.
1 parent 91a5751 commit a86d542

File tree

5 files changed

+131
-53
lines changed

5 files changed

+131
-53
lines changed

include/vcpkg/base/diagnostics.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,6 @@ namespace vcpkg
196196
DiagnosticContext& status_context;
197197
};
198198

199-
struct FullyBufferedDiagnosticContext;
200-
201199
struct DiagnosticOrMessageLine
202200
{
203201
DiagnosticOrMessageLine(const DiagnosticLine& dl);

include/vcpkg/base/fwd/diagnostics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ namespace vcpkg
1616
struct DiagnosticLine;
1717
struct DiagnosticContext;
1818
struct PrintingDiagnosticContext;
19+
struct BasicBufferedDiagnosticContext;
1920
struct SinkBufferedDiagnosticContext;
21+
struct ContextBufferedDiagnosticContext;
2022
struct FullyBufferedDiagnosticContext;
2123
struct AttemptDiagnosticContext;
2224
struct WarningDiagnosticContext;

include/vcpkg/tools.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@
77

88
#include <vcpkg/fwd/tools.h>
99

10+
#include <vcpkg/base/cache.h>
11+
#include <vcpkg/base/expected.h>
1012
#include <vcpkg/base/stringview.h>
1113

14+
#include <functional>
15+
#include <map>
1216
#include <string>
17+
#include <tuple>
18+
#include <utility>
1319

1420
namespace vcpkg
1521
{
@@ -68,4 +74,55 @@ namespace vcpkg
6874
Path config_path,
6975
Path tools,
7076
RequireExactVersions abiToolVersionHandling);
77+
78+
template<class Key, class Value, class Compare = std::less<>>
79+
struct ContextCache
80+
{
81+
template<class KeyIsh,
82+
class F,
83+
std::enable_if_t<std::is_constructible_v<Key, const KeyIsh&> &&
84+
detail::is_callable<Compare&, const Key&, const KeyIsh&>::value,
85+
int> = 0>
86+
const Value* get_lazy(DiagnosticContext& context, const KeyIsh& k, F&& f) const
87+
{
88+
auto it = m_cache.lower_bound(k);
89+
// lower_bound returns the first iterator such that it->first is greater than or equal to than k, so k must
90+
// be less than or equal to it->first. If k is greater than it->first, then it must be non-equal so we
91+
// have a cache miss.
92+
if (it == m_cache.end() || m_cache.key_comp()(k, it->first))
93+
{
94+
ContextBufferedDiagnosticContext cbdc{context};
95+
auto maybe_result = f(cbdc);
96+
if (auto success = maybe_result.get())
97+
{
98+
it = m_cache.emplace_hint(it,
99+
std::piecewise_construct,
100+
std::forward_as_tuple(k),
101+
std::forward_as_tuple(std::move(*success), expected_left_tag));
102+
}
103+
else
104+
{
105+
it = m_cache.emplace_hint(it,
106+
std::piecewise_construct,
107+
std::forward_as_tuple(k),
108+
std::forward_as_tuple(std::move(cbdc.lines), expected_right_tag));
109+
}
110+
}
111+
112+
if (auto success = it->second.get())
113+
{
114+
return success;
115+
}
116+
117+
for (const auto& line : it->second.error())
118+
{
119+
context.report(line);
120+
}
121+
122+
return nullptr;
123+
}
124+
125+
private:
126+
mutable std::map<Key, ExpectedT<Value, std::vector<DiagnosticLine>>, Compare> m_cache;
127+
};
71128
}

src/vcpkg-test/tools.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,3 +374,75 @@ TEST_CASE ("parse_tool_data errors", "[tools]")
374374
"SHA-512 hash must be 128 characters long and contain only hexadecimal digits");
375375
}
376376
}
377+
378+
TEST_CASE ("ContextCache", "[tools]")
379+
{
380+
struct JustOpt
381+
{
382+
int value;
383+
Optional<int> operator()(DiagnosticContext& context) const
384+
{
385+
context.statusln(LocalizedString::from_raw(fmt::format("The value is {}", value)));
386+
return value;
387+
}
388+
};
389+
390+
ContextCache<std::string, int> cache;
391+
392+
// success miss then hit (middle key)
393+
FullyBufferedDiagnosticContext fbdc1;
394+
const auto* first_ptr = cache.get_lazy(fbdc1, "durian", JustOpt{42});
395+
REQUIRE(first_ptr != nullptr);
396+
CHECK(*first_ptr == 42);
397+
CHECK(fbdc1.to_string() == "The value is 42");
398+
// functor should NOT run, status lines not replayed:
399+
FullyBufferedDiagnosticContext fbdc1_hit;
400+
const auto* hit_ptr = cache.get_lazy(fbdc1_hit, "durian", JustOpt{12345});
401+
REQUIRE(hit_ptr == first_ptr);
402+
CHECK(fbdc1_hit.empty());
403+
404+
// insert before existing element
405+
FullyBufferedDiagnosticContext fbdc2;
406+
const auto* below_ptr = cache.get_lazy(fbdc2, "apple", JustOpt{1729});
407+
REQUIRE(below_ptr != nullptr);
408+
CHECK(*below_ptr == 1729);
409+
CHECK(fbdc2.to_string() == "The value is 1729");
410+
FullyBufferedDiagnosticContext fbdc2_hit;
411+
const auto* below_hit_ptr = cache.get_lazy(fbdc2_hit, "apple", JustOpt{1});
412+
REQUIRE(below_hit_ptr == below_ptr);
413+
CHECK(fbdc2_hit.empty());
414+
415+
// insert above existing element
416+
FullyBufferedDiagnosticContext fbdc3;
417+
const auto* above_ptr = cache.get_lazy(fbdc3, "melon", JustOpt{1234});
418+
REQUIRE(above_ptr != nullptr);
419+
CHECK(*above_ptr == 1234);
420+
CHECK(fbdc3.to_string() == "The value is 1234");
421+
FullyBufferedDiagnosticContext fbdc3_hit;
422+
const auto* above_hit_ptr = cache.get_lazy(fbdc3_hit, "melon", JustOpt{2});
423+
REQUIRE(above_hit_ptr == above_ptr);
424+
CHECK(fbdc3_hit.empty());
425+
426+
// error case: provider returns empty optional and reports diagnostic; ensure cached error re-reports but provider
427+
// not re-run
428+
int error_call_count = 0;
429+
auto failing_provider = [&error_call_count](DiagnosticContext& ctx) -> Optional<int> {
430+
++error_call_count;
431+
ctx.statusln(LocalizedString::from_raw(fmt::format("The number of calls is {}", error_call_count)));
432+
ctx.report_error(LocalizedString::from_raw("bad"));
433+
return nullopt; // failure
434+
};
435+
FullyBufferedDiagnosticContext fbdc_err1;
436+
const auto* err1 = cache.get_lazy(fbdc_err1, "kiwi", failing_provider);
437+
REQUIRE(err1 == nullptr);
438+
CHECK(!fbdc_err1.empty());
439+
CHECK(fbdc_err1.to_string() == "The number of calls is 1\nerror: bad");
440+
441+
FullyBufferedDiagnosticContext fbdc_err2;
442+
const auto* err2 = cache.get_lazy(fbdc_err2, "kiwi", failing_provider); // should not invoke provider again
443+
REQUIRE(err2 == nullptr);
444+
CHECK(!fbdc_err2.empty());
445+
CHECK(fbdc_err2.to_string() == "error: bad"); // status line not replayed
446+
const auto second_error_output = fbdc_err2.to_string();
447+
CHECK(error_call_count == 1);
448+
}

src/vcpkg/tools.cpp

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -43,57 +43,6 @@ namespace
4343
{"netbsd", ToolOs::NetBsd},
4444
{"solaris", ToolOs::Solaris},
4545
};
46-
47-
template<class Key, class Value, class Compare = std::less<>>
48-
struct ContextCache
49-
{
50-
template<class KeyIsh,
51-
class F,
52-
std::enable_if_t<std::is_constructible_v<Key, const KeyIsh&> &&
53-
detail::is_callable<Compare&, const Key&, const KeyIsh&>::value,
54-
int> = 0>
55-
const Value* get_lazy(DiagnosticContext& context, const KeyIsh& k, F&& f) const
56-
{
57-
auto it = m_cache.lower_bound(k);
58-
// lower_bound returns the first iterator such that it->first is greater than or equal to than k, so k must
59-
// be less than or equal to it->first. If k is greater than or equal it->first, then it must be equal so we
60-
// have a cache hit.
61-
if (it == m_cache.end() || m_cache.key_comp()(k, it->first))
62-
{
63-
ContextBufferedDiagnosticContext cbdc{context};
64-
auto maybe_result = f(context);
65-
if (auto success = maybe_result.get())
66-
{
67-
it = m_cache.emplace_hint(it,
68-
std::piecewise_construct,
69-
std::forward_as_tuple(k),
70-
std::forward_as_tuple(std::move(*success), expected_left_tag));
71-
}
72-
else
73-
{
74-
it = m_cache.emplace_hint(it,
75-
std::piecewise_construct,
76-
std::forward_as_tuple(k),
77-
std::forward_as_tuple(std::move(cbdc.lines), expected_right_tag));
78-
}
79-
}
80-
81-
if (auto success = it->second.get())
82-
{
83-
return success;
84-
}
85-
86-
for (const auto& line : it->second.error())
87-
{
88-
context.report(line);
89-
}
90-
91-
return nullptr;
92-
}
93-
94-
private:
95-
mutable std::map<Key, ExpectedT<Value, std::vector<DiagnosticLine>>, Compare> m_cache;
96-
};
9746
}
9847

9948
namespace vcpkg

0 commit comments

Comments
 (0)