Loading tools/aapt2/ResourceValues.cpp +68 −9 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include "io/File.h" #include "io/File.h" #include "util/Util.h" #include "util/Util.h" #include <algorithm> #include <androidfw/ResourceTypes.h> #include <androidfw/ResourceTypes.h> #include <limits> #include <limits> Loading Loading @@ -302,18 +303,42 @@ Attribute::Attribute(bool w, uint32_t t) : mWeak = w; mWeak = w; } } template <typename T> T* addPointer(T& val) { return &val; } bool Attribute::equals(const Value* value) const { bool Attribute::equals(const Value* value) const { const Attribute* other = valueCast<Attribute>(value); const Attribute* other = valueCast<Attribute>(value); if (!other) { if (!other) { return false; return false; } } return this->typeMask == other->typeMask && this->minInt == other->minInt && if (symbols.size() != other->symbols.size()) { this->maxInt == other->maxInt && return false; std::equal(this->symbols.begin(), this->symbols.end(), } other->symbols.begin(), [](const Symbol& a, const Symbol& b) -> bool { if (typeMask != other->typeMask || minInt != other->minInt || maxInt != other->maxInt) { return a.symbol.equals(&b.symbol) && a.value == b.value; return false; } std::vector<const Symbol*> sortedA; std::transform(symbols.begin(), symbols.end(), std::back_inserter(sortedA), addPointer<const Symbol>); std::sort(sortedA.begin(), sortedA.end(), [](const Symbol* a, const Symbol* b) -> bool { return a->symbol.name < b->symbol.name; }); std::vector<const Symbol*> sortedB; std::transform(other->symbols.begin(), other->symbols.end(), std::back_inserter(sortedB), addPointer<const Symbol>); std::sort(sortedB.begin(), sortedB.end(), [](const Symbol* a, const Symbol* b) -> bool { return a->symbol.name < b->symbol.name; }); return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(), [](const Symbol* a, const Symbol* b) -> bool { return a->symbol.equals(&b->symbol) && a->value == b->value; }); }); } } Loading Loading @@ -526,9 +551,28 @@ bool Style::equals(const Value* value) const { (parent && other->parent && !parent.value().equals(&other->parent.value()))) { (parent && other->parent && !parent.value().equals(&other->parent.value()))) { return false; return false; } } return std::equal(entries.begin(), entries.end(), other->entries.begin(), [](const Entry& a, const Entry& b) -> bool { if (entries.size() != other->entries.size()) { return a.key.equals(&b.key) && a.value->equals(b.value.get()); return false; } std::vector<const Entry*> sortedA; std::transform(entries.begin(), entries.end(), std::back_inserter(sortedA), addPointer<const Entry>); std::sort(sortedA.begin(), sortedA.end(), [](const Entry* a, const Entry* b) -> bool { return a->key.name < b->key.name; }); std::vector<const Entry*> sortedB; std::transform(other->entries.begin(), other->entries.end(), std::back_inserter(sortedB), addPointer<const Entry>); std::sort(sortedB.begin(), sortedB.end(), [](const Entry* a, const Entry* b) -> bool { return a->key.name < b->key.name; }); return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(), [](const Entry* a, const Entry* b) -> bool { return a->key.equals(&b->key) && a->value->equals(b->value.get()); }); }); } } Loading Loading @@ -563,6 +607,8 @@ void Style::print(std::ostream* out) const { static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) { static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) { if (value.key.name) { if (value.key.name) { out << value.key.name.value(); out << value.key.name.value(); } else if (value.key.id) { out << value.key.id.value(); } else { } else { out << "???"; out << "???"; } } Loading @@ -577,6 +623,10 @@ bool Array::equals(const Value* value) const { return false; return false; } } if (items.size() != other->items.size()) { return false; } return std::equal(items.begin(), items.end(), other->items.begin(), return std::equal(items.begin(), items.end(), other->items.begin(), [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { return a->equals(b.get()); return a->equals(b.get()); Loading Loading @@ -605,6 +655,10 @@ bool Plural::equals(const Value* value) const { return false; return false; } } if (values.size() != other->values.size()) { return false; } return std::equal(values.begin(), values.end(), other->values.begin(), return std::equal(values.begin(), values.end(), other->values.begin(), [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { if (bool(a) != bool(b)) { if (bool(a) != bool(b)) { Loading Loading @@ -659,6 +713,11 @@ bool Styleable::equals(const Value* value) const { if (!other) { if (!other) { return false; return false; } } if (entries.size() != other->entries.size()) { return false; } return std::equal(entries.begin(), entries.end(), other->entries.begin(), return std::equal(entries.begin(), entries.end(), other->entries.begin(), [](const Reference& a, const Reference& b) -> bool { [](const Reference& a, const Reference& b) -> bool { return a.equals(&b); return a.equals(&b); Loading tools/aapt2/diff/Diff.cpp +23 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "Flags.h" #include "Flags.h" #include "ResourceTable.h" #include "ResourceTable.h" #include "ValueVisitor.h" #include "io/ZipArchive.h" #include "io/ZipArchive.h" #include "process/IResourceTableConsumer.h" #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" #include "process/SymbolTable.h" Loading Loading @@ -385,6 +386,24 @@ static bool emitResourceTableDiff(IAaptContext* context, LoadedApk* apkA, Loaded return diff; return diff; } } class ZeroingReferenceVisitor : public ValueVisitor { public: using ValueVisitor::visit; void visit(Reference* ref) override { if (ref->name && ref->id) { if (ref->id.value().packageId() == 0x7f) { ref->id = {}; } } } }; static void zeroOutAppReferences(ResourceTable* table) { ZeroingReferenceVisitor visitor; visitAllValuesInTable(table, &visitor); } int diff(const std::vector<StringPiece>& args) { int diff(const std::vector<StringPiece>& args) { DiffContext context; DiffContext context; Loading @@ -405,6 +424,10 @@ int diff(const std::vector<StringPiece>& args) { return 1; return 1; } } // Zero out Application IDs in references. zeroOutAppReferences(apkA->getResourceTable()); zeroOutAppReferences(apkB->getResourceTable()); if (emitResourceTableDiff(&context, apkA.get(), apkB.get())) { if (emitResourceTableDiff(&context, apkA.get(), apkB.get())) { // We emitted a diff, so return 1 (failure). // We emitted a diff, so return 1 (failure). return 1; return 1; Loading tools/aapt2/dump/Dump.cpp +50 −33 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "io/ZipArchive.h" #include "io/ZipArchive.h" #include "process/IResourceTableConsumer.h" #include "process/IResourceTableConsumer.h" #include "proto/ProtoSerialize.h" #include "proto/ProtoSerialize.h" #include "unflatten/BinaryResourceParser.h" #include "util/Files.h" #include "util/Files.h" #include "util/StringPiece.h" #include "util/StringPiece.h" Loading @@ -44,18 +45,9 @@ void dumpCompiledFile(const pb::CompiledFile& pbFile, const void* data, size_t l << "Source: " << file->source << "\n"; << "Source: " << file->source << "\n"; } } void dumpCompiledTable(const pb::ResourceTable& pbTable, const Source& source, IAaptContext* context) { std::unique_ptr<ResourceTable> table = deserializeTableFromPb(pbTable, source, context->getDiagnostics()); if (!table) { return; } Debug::printTable(table.get()); } void tryDumpFile(IAaptContext* context, const std::string& filePath) { void tryDumpFile(IAaptContext* context, const std::string& filePath) { std::unique_ptr<ResourceTable> table; std::string err; std::string err; std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::create(filePath, &err); std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::create(filePath, &err); if (zip) { if (zip) { Loading @@ -75,17 +67,34 @@ void tryDumpFile(IAaptContext* context, const std::string& filePath) { return; return; } } std::unique_ptr<ResourceTable> table = deserializeTableFromPb( table = deserializeTableFromPb( pbTable, Source(filePath), context->getDiagnostics()); pbTable, Source(filePath), context->getDiagnostics()); if (table) { if (!table) { DebugPrintTableOptions debugPrintTableOptions; return; debugPrintTableOptions.showSources = true; Debug::printTable(table.get(), debugPrintTableOptions); } } } } if (!table) { file = zip->findFile("resources.arsc"); if (file) { std::unique_ptr<io::IData> data = file->openAsData(); if (!data) { context->getDiagnostics()->error(DiagMessage(filePath) << "failed to open resources.arsc"); return; return; } } table = util::make_unique<ResourceTable>(); BinaryResourceParser parser(context, table.get(), Source(filePath), data->data(), data->size()); if (!parser.parse()) { return; } } } } if (!table) { Maybe<android::FileMap> file = file::mmapPath(filePath, &err); Maybe<android::FileMap> file = file::mmapPath(filePath, &err); if (!file) { if (!file) { context->getDiagnostics()->error(DiagMessage(filePath) << err); context->getDiagnostics()->error(DiagMessage(filePath) << err); Loading @@ -97,10 +106,10 @@ void tryDumpFile(IAaptContext* context, const std::string& filePath) { // Try as a compiled table. // Try as a compiled table. pb::ResourceTable pbTable; pb::ResourceTable pbTable; if (pbTable.ParseFromArray(fileMap->getDataPtr(), fileMap->getDataLength())) { if (pbTable.ParseFromArray(fileMap->getDataPtr(), fileMap->getDataLength())) { dumpCompiledTable(pbTable, Source(filePath), context); table = deserializeTableFromPb(pbTable, Source(filePath), context->getDiagnostics()); return; } } if (!table) { // Try as a compiled file. // Try as a compiled file. CompiledFileInputStream input(fileMap->getDataPtr(), fileMap->getDataLength()); CompiledFileInputStream input(fileMap->getDataPtr(), fileMap->getDataLength()); if (const pb::CompiledFile* pbFile = input.CompiledFile()) { if (const pb::CompiledFile* pbFile = input.CompiledFile()) { Loading @@ -108,6 +117,14 @@ void tryDumpFile(IAaptContext* context, const std::string& filePath) { return; return; } } } } } if (table) { DebugPrintTableOptions debugPrintTableOptions; debugPrintTableOptions.showSources = true; Debug::printTable(table.get(), debugPrintTableOptions); } } class DumpContext : public IAaptContext { class DumpContext : public IAaptContext { public: public: Loading tools/aapt2/unflatten/BinaryResourceParser.cpp +0 −1 Original line number Original line Diff line number Diff line Loading @@ -61,7 +61,6 @@ public: auto cacheIter = mMapping->find(id); auto cacheIter = mMapping->find(id); if (cacheIter != mMapping->end()) { if (cacheIter != mMapping->end()) { reference->name = cacheIter->second; reference->name = cacheIter->second; reference->id = {}; } } } } }; }; Loading tools/aapt2/util/Maybe.h +23 −0 Original line number Original line Diff line number Diff line Loading @@ -88,6 +88,8 @@ public: */ */ const T& value() const; const T& value() const; T valueOrDefault(const T& def) const; private: private: template <typename U> template <typename U> friend class Maybe; friend class Maybe; Loading Loading @@ -262,6 +264,14 @@ const T& Maybe<T>::value() const { return reinterpret_cast<const T&>(mStorage); return reinterpret_cast<const T&>(mStorage); } } template <typename T> T Maybe<T>::valueOrDefault(const T& def) const { if (mNothing) { return def; } return reinterpret_cast<const T&>(mStorage); } template <typename T> template <typename T> void Maybe<T>::destroy() { void Maybe<T>::destroy() { reinterpret_cast<T&>(mStorage).~T(); reinterpret_cast<T&>(mStorage).~T(); Loading Loading @@ -306,6 +316,19 @@ typename std::enable_if< return !(a == b); return !(a == b); } } template <typename T, typename U> typename std::enable_if< has_lt_op<T, U>::value, bool >::type operator<(const Maybe<T>& a, const Maybe<U>& b) { if (a && b) { return a.value() < b.value(); } else if (!a && !b) { return false; } return !a; } } // namespace aapt } // namespace aapt #endif // AAPT_MAYBE_H #endif // AAPT_MAYBE_H Loading
tools/aapt2/ResourceValues.cpp +68 −9 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include "io/File.h" #include "io/File.h" #include "util/Util.h" #include "util/Util.h" #include <algorithm> #include <androidfw/ResourceTypes.h> #include <androidfw/ResourceTypes.h> #include <limits> #include <limits> Loading Loading @@ -302,18 +303,42 @@ Attribute::Attribute(bool w, uint32_t t) : mWeak = w; mWeak = w; } } template <typename T> T* addPointer(T& val) { return &val; } bool Attribute::equals(const Value* value) const { bool Attribute::equals(const Value* value) const { const Attribute* other = valueCast<Attribute>(value); const Attribute* other = valueCast<Attribute>(value); if (!other) { if (!other) { return false; return false; } } return this->typeMask == other->typeMask && this->minInt == other->minInt && if (symbols.size() != other->symbols.size()) { this->maxInt == other->maxInt && return false; std::equal(this->symbols.begin(), this->symbols.end(), } other->symbols.begin(), [](const Symbol& a, const Symbol& b) -> bool { if (typeMask != other->typeMask || minInt != other->minInt || maxInt != other->maxInt) { return a.symbol.equals(&b.symbol) && a.value == b.value; return false; } std::vector<const Symbol*> sortedA; std::transform(symbols.begin(), symbols.end(), std::back_inserter(sortedA), addPointer<const Symbol>); std::sort(sortedA.begin(), sortedA.end(), [](const Symbol* a, const Symbol* b) -> bool { return a->symbol.name < b->symbol.name; }); std::vector<const Symbol*> sortedB; std::transform(other->symbols.begin(), other->symbols.end(), std::back_inserter(sortedB), addPointer<const Symbol>); std::sort(sortedB.begin(), sortedB.end(), [](const Symbol* a, const Symbol* b) -> bool { return a->symbol.name < b->symbol.name; }); return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(), [](const Symbol* a, const Symbol* b) -> bool { return a->symbol.equals(&b->symbol) && a->value == b->value; }); }); } } Loading Loading @@ -526,9 +551,28 @@ bool Style::equals(const Value* value) const { (parent && other->parent && !parent.value().equals(&other->parent.value()))) { (parent && other->parent && !parent.value().equals(&other->parent.value()))) { return false; return false; } } return std::equal(entries.begin(), entries.end(), other->entries.begin(), [](const Entry& a, const Entry& b) -> bool { if (entries.size() != other->entries.size()) { return a.key.equals(&b.key) && a.value->equals(b.value.get()); return false; } std::vector<const Entry*> sortedA; std::transform(entries.begin(), entries.end(), std::back_inserter(sortedA), addPointer<const Entry>); std::sort(sortedA.begin(), sortedA.end(), [](const Entry* a, const Entry* b) -> bool { return a->key.name < b->key.name; }); std::vector<const Entry*> sortedB; std::transform(other->entries.begin(), other->entries.end(), std::back_inserter(sortedB), addPointer<const Entry>); std::sort(sortedB.begin(), sortedB.end(), [](const Entry* a, const Entry* b) -> bool { return a->key.name < b->key.name; }); return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(), [](const Entry* a, const Entry* b) -> bool { return a->key.equals(&b->key) && a->value->equals(b->value.get()); }); }); } } Loading Loading @@ -563,6 +607,8 @@ void Style::print(std::ostream* out) const { static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) { static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) { if (value.key.name) { if (value.key.name) { out << value.key.name.value(); out << value.key.name.value(); } else if (value.key.id) { out << value.key.id.value(); } else { } else { out << "???"; out << "???"; } } Loading @@ -577,6 +623,10 @@ bool Array::equals(const Value* value) const { return false; return false; } } if (items.size() != other->items.size()) { return false; } return std::equal(items.begin(), items.end(), other->items.begin(), return std::equal(items.begin(), items.end(), other->items.begin(), [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { return a->equals(b.get()); return a->equals(b.get()); Loading Loading @@ -605,6 +655,10 @@ bool Plural::equals(const Value* value) const { return false; return false; } } if (values.size() != other->values.size()) { return false; } return std::equal(values.begin(), values.end(), other->values.begin(), return std::equal(values.begin(), values.end(), other->values.begin(), [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { if (bool(a) != bool(b)) { if (bool(a) != bool(b)) { Loading Loading @@ -659,6 +713,11 @@ bool Styleable::equals(const Value* value) const { if (!other) { if (!other) { return false; return false; } } if (entries.size() != other->entries.size()) { return false; } return std::equal(entries.begin(), entries.end(), other->entries.begin(), return std::equal(entries.begin(), entries.end(), other->entries.begin(), [](const Reference& a, const Reference& b) -> bool { [](const Reference& a, const Reference& b) -> bool { return a.equals(&b); return a.equals(&b); Loading
tools/aapt2/diff/Diff.cpp +23 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "Flags.h" #include "Flags.h" #include "ResourceTable.h" #include "ResourceTable.h" #include "ValueVisitor.h" #include "io/ZipArchive.h" #include "io/ZipArchive.h" #include "process/IResourceTableConsumer.h" #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" #include "process/SymbolTable.h" Loading Loading @@ -385,6 +386,24 @@ static bool emitResourceTableDiff(IAaptContext* context, LoadedApk* apkA, Loaded return diff; return diff; } } class ZeroingReferenceVisitor : public ValueVisitor { public: using ValueVisitor::visit; void visit(Reference* ref) override { if (ref->name && ref->id) { if (ref->id.value().packageId() == 0x7f) { ref->id = {}; } } } }; static void zeroOutAppReferences(ResourceTable* table) { ZeroingReferenceVisitor visitor; visitAllValuesInTable(table, &visitor); } int diff(const std::vector<StringPiece>& args) { int diff(const std::vector<StringPiece>& args) { DiffContext context; DiffContext context; Loading @@ -405,6 +424,10 @@ int diff(const std::vector<StringPiece>& args) { return 1; return 1; } } // Zero out Application IDs in references. zeroOutAppReferences(apkA->getResourceTable()); zeroOutAppReferences(apkB->getResourceTable()); if (emitResourceTableDiff(&context, apkA.get(), apkB.get())) { if (emitResourceTableDiff(&context, apkA.get(), apkB.get())) { // We emitted a diff, so return 1 (failure). // We emitted a diff, so return 1 (failure). return 1; return 1; Loading
tools/aapt2/dump/Dump.cpp +50 −33 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "io/ZipArchive.h" #include "io/ZipArchive.h" #include "process/IResourceTableConsumer.h" #include "process/IResourceTableConsumer.h" #include "proto/ProtoSerialize.h" #include "proto/ProtoSerialize.h" #include "unflatten/BinaryResourceParser.h" #include "util/Files.h" #include "util/Files.h" #include "util/StringPiece.h" #include "util/StringPiece.h" Loading @@ -44,18 +45,9 @@ void dumpCompiledFile(const pb::CompiledFile& pbFile, const void* data, size_t l << "Source: " << file->source << "\n"; << "Source: " << file->source << "\n"; } } void dumpCompiledTable(const pb::ResourceTable& pbTable, const Source& source, IAaptContext* context) { std::unique_ptr<ResourceTable> table = deserializeTableFromPb(pbTable, source, context->getDiagnostics()); if (!table) { return; } Debug::printTable(table.get()); } void tryDumpFile(IAaptContext* context, const std::string& filePath) { void tryDumpFile(IAaptContext* context, const std::string& filePath) { std::unique_ptr<ResourceTable> table; std::string err; std::string err; std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::create(filePath, &err); std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::create(filePath, &err); if (zip) { if (zip) { Loading @@ -75,17 +67,34 @@ void tryDumpFile(IAaptContext* context, const std::string& filePath) { return; return; } } std::unique_ptr<ResourceTable> table = deserializeTableFromPb( table = deserializeTableFromPb( pbTable, Source(filePath), context->getDiagnostics()); pbTable, Source(filePath), context->getDiagnostics()); if (table) { if (!table) { DebugPrintTableOptions debugPrintTableOptions; return; debugPrintTableOptions.showSources = true; Debug::printTable(table.get(), debugPrintTableOptions); } } } } if (!table) { file = zip->findFile("resources.arsc"); if (file) { std::unique_ptr<io::IData> data = file->openAsData(); if (!data) { context->getDiagnostics()->error(DiagMessage(filePath) << "failed to open resources.arsc"); return; return; } } table = util::make_unique<ResourceTable>(); BinaryResourceParser parser(context, table.get(), Source(filePath), data->data(), data->size()); if (!parser.parse()) { return; } } } } if (!table) { Maybe<android::FileMap> file = file::mmapPath(filePath, &err); Maybe<android::FileMap> file = file::mmapPath(filePath, &err); if (!file) { if (!file) { context->getDiagnostics()->error(DiagMessage(filePath) << err); context->getDiagnostics()->error(DiagMessage(filePath) << err); Loading @@ -97,10 +106,10 @@ void tryDumpFile(IAaptContext* context, const std::string& filePath) { // Try as a compiled table. // Try as a compiled table. pb::ResourceTable pbTable; pb::ResourceTable pbTable; if (pbTable.ParseFromArray(fileMap->getDataPtr(), fileMap->getDataLength())) { if (pbTable.ParseFromArray(fileMap->getDataPtr(), fileMap->getDataLength())) { dumpCompiledTable(pbTable, Source(filePath), context); table = deserializeTableFromPb(pbTable, Source(filePath), context->getDiagnostics()); return; } } if (!table) { // Try as a compiled file. // Try as a compiled file. CompiledFileInputStream input(fileMap->getDataPtr(), fileMap->getDataLength()); CompiledFileInputStream input(fileMap->getDataPtr(), fileMap->getDataLength()); if (const pb::CompiledFile* pbFile = input.CompiledFile()) { if (const pb::CompiledFile* pbFile = input.CompiledFile()) { Loading @@ -108,6 +117,14 @@ void tryDumpFile(IAaptContext* context, const std::string& filePath) { return; return; } } } } } if (table) { DebugPrintTableOptions debugPrintTableOptions; debugPrintTableOptions.showSources = true; Debug::printTable(table.get(), debugPrintTableOptions); } } class DumpContext : public IAaptContext { class DumpContext : public IAaptContext { public: public: Loading
tools/aapt2/unflatten/BinaryResourceParser.cpp +0 −1 Original line number Original line Diff line number Diff line Loading @@ -61,7 +61,6 @@ public: auto cacheIter = mMapping->find(id); auto cacheIter = mMapping->find(id); if (cacheIter != mMapping->end()) { if (cacheIter != mMapping->end()) { reference->name = cacheIter->second; reference->name = cacheIter->second; reference->id = {}; } } } } }; }; Loading
tools/aapt2/util/Maybe.h +23 −0 Original line number Original line Diff line number Diff line Loading @@ -88,6 +88,8 @@ public: */ */ const T& value() const; const T& value() const; T valueOrDefault(const T& def) const; private: private: template <typename U> template <typename U> friend class Maybe; friend class Maybe; Loading Loading @@ -262,6 +264,14 @@ const T& Maybe<T>::value() const { return reinterpret_cast<const T&>(mStorage); return reinterpret_cast<const T&>(mStorage); } } template <typename T> T Maybe<T>::valueOrDefault(const T& def) const { if (mNothing) { return def; } return reinterpret_cast<const T&>(mStorage); } template <typename T> template <typename T> void Maybe<T>::destroy() { void Maybe<T>::destroy() { reinterpret_cast<T&>(mStorage).~T(); reinterpret_cast<T&>(mStorage).~T(); Loading Loading @@ -306,6 +316,19 @@ typename std::enable_if< return !(a == b); return !(a == b); } } template <typename T, typename U> typename std::enable_if< has_lt_op<T, U>::value, bool >::type operator<(const Maybe<T>& a, const Maybe<U>& b) { if (a && b) { return a.value() < b.value(); } else if (!a && !b) { return false; } return !a; } } // namespace aapt } // namespace aapt #endif // AAPT_MAYBE_H #endif // AAPT_MAYBE_H