summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorArne Juul <arnej@verizonmedia.com>2020-07-14 13:58:59 +0000
committerArne Juul <arnej@verizonmedia.com>2020-07-15 15:39:24 +0000
commit9516755ab329d311af3492aedd70102130bac371 (patch)
tree796c6910e4d569e6e2955c93ecfb01e508870a3e /searchlib
parent9debffd31d309a7fe4062241a731d5722f4199e0 (diff)
add files for GeoLocationParser class
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location_parser.cpp243
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location_parser.h67
2 files changed, 310 insertions, 0 deletions
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 <limits>
+#include <vespa/vespalib/stllike/asciistream.h>
+
+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 <unnamed>
+
+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<uint32_t>::max()),
+ _min_x(std::numeric_limits<int32_t>::min()),
+ _max_x(std::numeric_limits<int32_t>::max()),
+ _min_y(std::numeric_limits<int32_t>::min()),
+ _max_y(std::numeric_limits<int32_t>::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 <string>
+#include <cstdint>
+#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