From 9516755ab329d311af3492aedd70102130bac371 Mon Sep 17 00:00:00 2001 From: Arne Juul Date: Tue, 14 Jul 2020 13:58:59 +0000 Subject: add files for GeoLocationParser class --- .../vespa/searchlib/common/geo_location_parser.cpp | 243 +++++++++++++++++++++ .../vespa/searchlib/common/geo_location_parser.h | 67 ++++++ 2 files changed, 310 insertions(+) create mode 100644 searchlib/src/vespa/searchlib/common/geo_location_parser.cpp create mode 100644 searchlib/src/vespa/searchlib/common/geo_location_parser.h (limited to 'searchlib') diff --git a/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp b/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp new file mode 100644 index 00000000000..8abf65bd3ee --- /dev/null +++ b/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp @@ -0,0 +1,243 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "geo_location_parser.h" +#include +#include + +namespace { + +int getInt(const char * &p) { + int val; + bool isminus; + val = 0; + isminus = false; + if (*p == '-') { + isminus = true; + p++; + } + while (*p >= '0' && *p <= '9') { + val *= 10; + val += (*p++ - '0'); + } + return isminus ? - val : val; +} + +} // namespace + +namespace search::common { + +GeoLocationParser::GeoLocationParser() + : _valid(false), + _has_point(false), + _has_bounding_box(false), + _field_name(), + _x(0), + _y(0), + _x_aspect(0u), + _radius(std::numeric_limits::max()), + _min_x(std::numeric_limits::min()), + _max_x(std::numeric_limits::max()), + _min_y(std::numeric_limits::min()), + _max_y(std::numeric_limits::max()), + _parseError(NULL) +{} + +std::string +GeoLocationParser::getOldFormatLocationString() const +{ + vespalib::asciistream loc; + if (hasPoint()) { + loc << "(2" // dimensionality + << "," << _x + << "," << _y + << "," << _radius + << "," << "0" // table id. + << "," << "1" // rank multiplier. + << "," << "0" // rank only on distance. + << "," << _x_aspect // aspect multiplier + << ")"; + } + if (hasBoundingBox()) { + loc << "[2," << _min_x + << "," << _min_y + << "," << _max_x + << "," << _max_y + << "]" ; + } + return loc.str(); +} + +std::string +GeoLocationParser::getOldFormatLocationStringWithField() const +{ + if (hasFieldName()) { + return getFieldName() + ":" + getOldFormatLocationString(); + } else { + return getOldFormatLocationString(); + } +} + + +bool +GeoLocationParser::getDimensionality(const char * &p) { + if (*p == '2') { + p++; + if (*p != ',') { + _parseError = "Missing comma after 2D dimensionality"; + return false; + } + p++; + return true; + } + _parseError = "Bad dimensionality spec, not 2D"; + return false; +} + +bool +GeoLocationParser::parseOldFormatWithField(const std::string &str) +{ + auto sep = str.find(':'); + if (sep == std::string::npos) { + _parseError = "Location string lacks field specification."; + return false; + } + _field_name = str.substr(0, sep); + std::string only_loc = str.substr(sep + 1); + return parseOldFormat(only_loc); +} + +bool +GeoLocationParser::parseOldFormat(const std::string &locStr) +{ + bool foundBoundingBox = false; + bool foundLoc = false; + const char *p = locStr.c_str(); + while (*p != '\0') { + if (*p == '[') { + p++; + if (foundBoundingBox) { + _parseError = "Duplicate bounding box"; + return false; + } + foundBoundingBox = true; + if (!getDimensionality(p)) + return false; + _min_x = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after minx"; + return false; + } + p++; + _min_y = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after miny"; + return false; + } + p++; + _max_x = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after maxx"; + return false; + } + p++; + _max_y = getInt(p); + if (*p != ']') { + _parseError = "Missing ']' after maxy"; + return false; + } + p++; + } else if (*p == '(') { + p++; + if (foundLoc) { + _parseError = "Duplicate location"; + return false; + } + foundLoc = true; + if (!getDimensionality(p)) + return false; + _x = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after x position"; + return false; + } + p++; + _y = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after y position"; + return false; + } + p++; + _radius = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after radius"; + return false; + } + p++; + /* _tableID = */ (void) getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after tableID"; + return false; + } + p++; + /* _rankMultiplier = */ (void) getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after rank multiplier"; + return false; + } + p++; + /* _rankOnlyOnDistance = */ (void) getInt(p); + if (*p == ',') { + p++; + _x_aspect = getInt(p); + if (*p != ')') { + _parseError = "Missing ')' after xAspect"; + return false; + } + } else { + if (*p != ')') { + _parseError = "Missing ')' after rankOnlyOnDistance flag"; + return false; + } + } + p++; + } else if (*p == ' ') { + p++; + } else { + _parseError = "Unexpected char in location spec"; + return false; + } + } + _has_point = foundLoc; + _has_bounding_box = foundBoundingBox; + _valid = (_has_point || _has_bounding_box); + return _valid; +} + +GeoLocation +GeoLocationParser::getGeoLocation() const +{ + GeoLocation::Aspect aspect(_x_aspect); + if (_has_bounding_box) { + GeoLocation::Range x_range{_min_x, _max_x}; + GeoLocation::Range y_range{_min_y, _max_y}; + GeoLocation::Box bounding_box{x_range, y_range}; + if (_has_point) { + GeoLocation::Point point{_x, _y}; + if (_radius == GeoLocation::radius_inf) { + return GeoLocation(bounding_box, point, aspect); + } + return GeoLocation(bounding_box, point, _radius, aspect); + } + return GeoLocation(bounding_box); + } + if (_has_point) { + GeoLocation::Point point{_x, _y}; + if (_radius == GeoLocation::radius_inf) { + return GeoLocation(point, aspect); + } + return GeoLocation(point, _radius, aspect); + } + return GeoLocation(); +} + +} // namespace diff --git a/searchlib/src/vespa/searchlib/common/geo_location_parser.h b/searchlib/src/vespa/searchlib/common/geo_location_parser.h new file mode 100644 index 00000000000..84c1a7cab07 --- /dev/null +++ b/searchlib/src/vespa/searchlib/common/geo_location_parser.h @@ -0,0 +1,67 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include +#include +#include "geo_location.h" +#include "geo_location_spec.h" + +namespace search::common { + +class GeoLocationParser +{ +public: + GeoLocationParser(); + + bool isValid() const { return _valid; } + bool hasPoint() const { return _has_point; } + bool hasBoundingBox() const { return _has_bounding_box; } + bool hasFieldName() const { return ! _field_name.empty(); } + + uint32_t getXAspect() const { return _x_aspect; } + int32_t getX() const { return _x; } + int32_t getY() const { return _y; } + uint32_t getRadius() const { return _radius; } + + int32_t getMinX() const { return _min_x; } + int32_t getMinY() const { return _min_y; } + int32_t getMaxX() const { return _max_x; } + int32_t getMaxY() const { return _max_y; } + + std::string getOldFormatLocationString() const; + std::string getOldFormatLocationStringWithField() const; + std::string getFieldName() const { return _field_name; } + + bool parseOldFormat(const std::string &locStr); + void setFieldName(const std::string &name) { _field_name = name; } + bool parseOldFormatWithField(const std::string &str); + GeoLocation getGeoLocation() const; +#if 0 + GeoLocationSpec spec() const { + return GeoLocationSpec{_field_name, getGeoLocation()}; + } +#endif + const char * getParseError() const { return _parseError; } + +private: + bool _valid; + bool _has_point; + bool _has_bounding_box; + + std::string _field_name; + + int32_t _x; /* Query X position */ + int32_t _y; /* Query Y position */ + uint32_t _x_aspect; /* X distance multiplier fraction */ + uint32_t _radius; /* Radius for euclidean distance */ + int32_t _min_x; /* Min X coordinate */ + int32_t _max_x; /* Max X coordinate */ + int32_t _min_y; /* Min Y coordinate */ + int32_t _max_y; /* Max Y coordinate */ + + const char *_parseError; + bool getDimensionality(const char * &p); +}; + +} // namespace -- cgit v1.2.3