Skip to content

Commit 9ece35c

Browse files
Mizuchifacebook-github-bot
authored andcommitted
Implement read APIs for MapPatch
Summary: This diff implemented `customVisit` to read Patch content. In addition, it's used to re-implement `merge` and `apply` methods. Reviewed By: vitaut Differential Revision: D45214368 fbshipit-source-id: 9eb7bfcbf1b214fcee9b379bba50afd3c835d518
1 parent 7947ab9 commit 9ece35c

File tree

1 file changed

+45
-39
lines changed

1 file changed

+45
-39
lines changed

third-party/thrift/src/thrift/lib/cpp2/op/detail/ContainerPatch.h

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -458,49 +458,54 @@ class MapPatch : public BaseContainerPatch<Patch, MapPatch<Patch>> {
458458
return (data_.add().value()[key], data_.patch()->operator[](key));
459459
}
460460

461-
void apply(T& val) const {
462-
if (applyAssignOrClear(val)) {
463-
return;
464-
}
465-
applyPatch(val, *data_.patchPrior());
466-
val.insert(data_.add()->begin(), data_.add()->end());
467-
erase_all(val, *data_.remove());
468-
for (const auto& entry : *data_.put()) {
469-
val.insert_or_assign(entry.first, entry.second);
461+
template <class Visitor>
462+
void customVisit(Visitor&& v) const {
463+
if (false) {
464+
// Test whether the required methods exist in Visitor
465+
v.assign(T{});
466+
v.clear();
467+
v.patchIfSet(P{});
468+
v.add(T{});
469+
v.put(T{});
470+
v.remove(std::unordered_set<typename T::key_type>{});
470471
}
471-
applyPatch(val, *data_.patch());
472-
}
473472

474-
/// @copydoc AssignPatch::merge
475-
template <typename U>
476-
void merge(U&& next) {
477-
if (mergeAssignAndClear(std::forward<U>(next))) {
473+
if (Base::template customVisitAssignAndClear(v)) {
478474
return;
479475
}
480476

481-
auto nextThrift = std::forward<U>(next).toThrift();
482-
if (data_.add()->empty() && data_.put()->empty() &&
483-
data_.remove()->empty()) {
484-
mergePatches(*data_.patchPrior(), *nextThrift.patchPrior());
485-
} else {
486-
for (auto&& kv : *nextThrift.patchPrior()) {
487-
// Move patches from patchPrior to patchAfter (aka patch) if current map
488-
// patch had given key added/remove/put
489-
patchByKey(kv.first).merge(kv.second);
477+
v.patchIfSet(*data_.patchPrior());
478+
v.add(*data_.add());
479+
v.remove(*data_.remove());
480+
v.put(*data_.put());
481+
v.patchIfSet(*data_.patch());
482+
}
483+
484+
void apply(T& val) const {
485+
struct Visitor {
486+
T& v;
487+
void assign(const T& t) { v = t; }
488+
void clear() { v.clear(); }
489+
void patchIfSet(const P& kv) {
490+
for (const auto& p : kv) {
491+
auto it = v.find(p.first);
492+
if (it != v.end()) {
493+
p.second.apply(it->second);
494+
}
495+
}
490496
}
491-
}
492-
add(*nextThrift.add());
493-
remove(*nextThrift.remove());
494-
put(*nextThrift.put());
495-
mergePatches(*data_.patch(), *nextThrift.patch());
496-
497-
// Cleanup keys that were removed in the final patch
498-
for (const auto& key : *data_.remove()) {
499-
data_.patchPrior()->erase(key);
500-
if (!isKeyModified(key)) {
501-
data_.patch()->erase(key);
497+
void remove(const std::unordered_set<typename T::key_type>& keys) {
498+
erase_all(v, keys);
502499
}
503-
}
500+
void add(const T& t) { v.insert(t.begin(), t.end()); }
501+
void put(const T& t) {
502+
for (const auto& entry : t) {
503+
v.insert_or_assign(entry.first, entry.second);
504+
}
505+
}
506+
};
507+
508+
return customVisit(Visitor{val});
504509
}
505510

506511
private:
@@ -519,9 +524,10 @@ class MapPatch : public BaseContainerPatch<Patch, MapPatch<Patch>> {
519524
}
520525
}
521526

522-
void mergePatches(P& ourPatch, P& otherPatch) {
523-
for (auto&& el : otherPatch) {
524-
ourPatch[el.first].merge(el.second);
527+
// Needed for merge(...). We can consider making this a public API.
528+
void patchIfSet(const P& patches) {
529+
for (auto&& ep : patches) {
530+
patchByKey(ep.first).merge(ep.second);
525531
}
526532
}
527533

0 commit comments

Comments
 (0)