//////////////////////////////////////////////////////////////////////////////// /// @brief Infrastructure for RangeInfo /// /// @file arangod/Aql/RangeInfo.h /// /// DISCLAIMER /// /// Copyright 2010-2014 triagens GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author not James /// @author Copyright 2014, triagens GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include #include "Basics/JsonHelper.h" #include "Aql/RangeInfo.h" using namespace triagens::basics; using namespace triagens::aql; using Json = triagens::basics::Json; //////////////////////////////////////////////////////////////////////////////// /// @brief 3-way comparison of the tightness of upper or lower constant /// RangeInfoBounds. /// Returns -1 if is tighter than , 1 if is tighter than /// , and 0 if the bounds are the same. The argument should be /// -1 if we are comparing lower bounds and 1 if we are comparing upper bounds. /// /// If or is a undefined, this indicates no bound. /// /// If ~ is the comparison and (x,y), (z,t) are RangeInfoBounds (i.e. x,z are /// Json values, y,t are booleans) that we are comparing as lower bounds, then /// the following holds: /// /// -1 x>z or (x=z, y=false, z=true) /// (x,y) ~ (z,t) = 0 x=z, y=t /// 1 z>x or (x=z, y=true, t=false) /// /// as upper bounds: /// /// -1 x(i))); } for (size_t i = 0; i < jsonHighList.size(); i++) { _highs.emplace_back(jsonHighList.at(static_cast(i))); } _lowConst.assign(json.get("lowConst")); _highConst.assign(json.get("highConst")); } //////////////////////////////////////////////////////////////////////////////// /// @brief toJson for a RangeInfo //////////////////////////////////////////////////////////////////////////////// triagens::basics::Json RangeInfo::toJson () const { triagens::basics::Json item(basics::Json::Array); item("variable", triagens::basics::Json(_var)) ("attr", triagens::basics::Json(_attr)) ("lowConst", _lowConst.toJson()) ("highConst", _highConst.toJson()); triagens::basics::Json lowList(triagens::basics::Json::List, _lows.size()); for (auto l : _lows) { lowList(l.toJson()); } item("lows", lowList); triagens::basics::Json highList(triagens::basics::Json::List, _highs.size()); for (auto h : _highs) { highList(h.toJson()); } item("highs", highList); item("valid", triagens::basics::Json(_valid)); item("equality", triagens::basics::Json(_equality)); return item; } //////////////////////////////////////////////////////////////////////////////// /// @brief class RangesInfo //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief insert if there is no range corresponding to variable name , /// and attribute , and otherwise intersection with existing range //////////////////////////////////////////////////////////////////////////////// void RangesInfo::insert (RangeInfo newRange) { TRI_ASSERT(newRange.isDefined()); std::unordered_map* oldMap = find(newRange._var); if (oldMap == nullptr) { std::unordered_map newMap; newMap.emplace(make_pair(newRange._attr, newRange)); _ranges.emplace(std::make_pair(newRange._var, newMap)); return; } auto it = oldMap->find(newRange._attr); if (it == oldMap->end()) { oldMap->emplace(make_pair(newRange._attr, newRange)); return; } RangeInfo& oldRange((*it).second); oldRange.fuse(newRange); } //////////////////////////////////////////////////////////////////////////////// ///// @brief fuse, fuse two ranges, must be for the same variable and attribute //////////////////////////////////////////////////////////////////////////////// void RangeInfo::fuse (RangeInfo const& that) { TRI_ASSERT(_var == that._var); TRI_ASSERT(_attr == that._attr); if (! isValid()) { // intersection of the empty set with any set is empty! return; } if (! that.isValid()) { // intersection of the empty set with any set is empty! invalidate(); return; } // The following is a corner case for constant bounds: if (_equality && that._equality && _lowConst.isDefined() && that._lowConst.isDefined()) { if (! TRI_CheckSameValueJson(_lowConst.bound().json(), that._lowConst.bound().json())) { invalidate(); return; } } // First sort out the constant low bounds: _lowConst.andCombineLowerBounds(that._lowConst); // Simply append the variable ones: for (auto l : that._lows) { _lows.emplace_back(l); } // Sort out the constant high bounds: _highConst.andCombineUpperBounds(that._highConst); // Simply append the variable ones: for (auto h : that._highs) { _highs.emplace_back(h); } // If either range knows that it can be at most one value, then this is // enough: _equality |= that._equality; // check the new constant range bounds are valid: if (_lowConst.isDefined() && _highConst.isDefined()) { int cmp = TRI_CompareValuesJson(_lowConst.bound().json(), _highConst.bound().json()); if (cmp == 1) { invalidate(); return; } if (cmp == 0) { if (! (_lowConst.inclusive() && _highConst.inclusive()) ) { // range invalid invalidate(); } else { _equality = true; // Can only be at most one value } } } } //////////////////////////////////////////////////////////////////////////////// /// @brief insert if there is no range corresponding to variable name , /// and attribute , and otherwise intersection with existing range //////////////////////////////////////////////////////////////////////////////// void RangesInfo::insert (std::string const& var, std::string const& name, RangeInfoBound low, RangeInfoBound high, bool equality) { insert(RangeInfo(var, name, low, high, equality)); }