/** * Copyright (C) 2018-present MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Server Side Public License, version 1, * as published by MongoDB, Inc. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Server Side Public License for more details. * * You should have received a copy of the Server Side Public License * along with this program. If not, see * . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the Server Side Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #pragma once #include #include #include #include "mongo/db/matcher/expression.h" namespace mongo { /** * Abstract base class for MatchExpressions that take a fixed 'nargs' number of MatchExpression * arguments. 'T' is the MatchExpression class that extends this interface. */ template class FixedArityMatchExpression : public MatchExpression { public: /** * The number of arguments accepted by this expression. */ static constexpr size_t arity() { return nargs; } virtual ~FixedArityMatchExpression() = default; void debugString(StringBuilder& debug, int indentationLevel) const final { _debugAddSpace(debug, indentationLevel); BSONObjBuilder builder; serialize(&builder); debug << builder.obj().toString(); } /** * The order of arguments is significant when determining equivalence. */ bool equivalent(const MatchExpression* expr) const final { if (matchType() != expr->matchType()) { return false; } auto other = static_cast(expr); const auto& ourChildren = _expressions; const auto& theirChildren = other->_expressions; return std::equal( ourChildren.begin(), ourChildren.end(), theirChildren.begin(), theirChildren.end(), [](const auto& expr1, const auto& expr2) { return expr1->equivalent(expr2.get()); }); } std::vector* getChildVector() final { return nullptr; } size_t numChildren() const final { return nargs; } MatchExpression* getChild(size_t i) const final { invariant(i < nargs); return _expressions[i].get(); } /** * The name of this MatchExpression. */ virtual StringData name() const = 0; /** * Serializes each subexpression sequentially in a BSONArray. */ void serialize(BSONObjBuilder* builder) const final { BSONArrayBuilder exprArray(builder->subarrayStart(name())); for (const auto& expr : _expressions) { BSONObjBuilder exprBuilder(exprArray.subobjStart()); expr->serialize(&exprBuilder); exprBuilder.doneFast(); } exprArray.doneFast(); } /** * Clones this MatchExpression by recursively cloning each sub-expression. */ std::unique_ptr shallowClone() const final { std::array, nargs> clonedExpressions; std::transform(_expressions.begin(), _expressions.end(), clonedExpressions.begin(), [](const auto& orig) { return orig ? orig->shallowClone() : std::unique_ptr(nullptr); }); std::unique_ptr clone = std::make_unique(std::move(clonedExpressions)); if (getTag()) { clone->setTag(getTag()->clone()); } return std::move(clone); } protected: /** * Takes ownership of the MatchExpressions in 'expressions'. */ explicit FixedArityMatchExpression( MatchType type, std::array, nargs> expressions) : MatchExpression(type), _expressions(std::move(expressions)) {} const auto& expressions() const { return _expressions; } private: ExpressionOptimizerFunc getOptimizer() const final { return [](std::unique_ptr expression) { for (auto& subExpression : static_cast(*expression)._expressions) { // Since 'subExpression' is a reference to a member of the // FixedArityMatchExpression's child array, this assignment replaces the original // child with the optimized child. subExpression = MatchExpression::optimize(std::move(subExpression)); } return expression; }; } std::array, nargs> _expressions; }; } // namespace mongo