Skip to content

Commit

Permalink
Continue reducing boost footprint
Browse files Browse the repository at this point in the history
  • Loading branch information
mmd-osm committed Jan 25, 2025
1 parent 4b2573c commit ba9f5d1
Show file tree
Hide file tree
Showing 8 changed files with 338 additions and 263 deletions.
10 changes: 5 additions & 5 deletions include/cgimap/api06/changeset_upload/relation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
#include "cgimap/util.hpp"

#include <optional>
#include <boost/algorithm/string/predicate.hpp>

#include <string>
#include <vector>

namespace api06 {

Expand All @@ -32,11 +32,11 @@ class RelationMember {

void set_type(const std::string &type) {

if (boost::iequals(type, "Node"))
if (iequals(type, "Node"))
m_type = "Node";
else if (boost::iequals(type, "Way"))
else if (iequals(type, "Way"))
m_type = "Way";
else if (boost::iequals(type, "Relation"))
else if (iequals(type, "Relation"))
m_type = "Relation";
else
throw payload_error(
Expand Down
74 changes: 74 additions & 0 deletions include/cgimap/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "cgimap/options.hpp"

#include <algorithm>
#include <charconv>
#include <clocale>
#include <cmath>
#include <cstdlib>
Expand Down Expand Up @@ -70,6 +71,79 @@ inline size_t unicode_strlen(const std::string & s)

#endif

inline bool ichar_equals(char a, char b) {
return a == b ||
std::tolower(static_cast<unsigned char>(a)) ==
std::tolower(static_cast<unsigned char>(b));
}

// Case insensitive string comparison
inline bool iequals(const std::string &a, const std::string &b) {
return a.size() == b.size() &&
std::equal(a.begin(), a.end(), b.begin(), b.end(), ichar_equals);
}

// Remove leading and trailing whitespace from string
inline std::string trim(const std::string &str) {
auto start = str.find_first_not_of(" \t\n\r");
if (start == std::string::npos)
return "";
auto end = str.find_last_not_of(" \t\n\r");
return str.substr(start, end - start + 1);
}

inline std::vector<std::string> split(const std::string &str, char delim,
bool trim_token) {
std::vector<std::string> tokens;
size_t start = 0;
size_t end = 0;

while ((end = str.find(delim, start)) != std::string::npos) {
if (end != start) {
std::string token = str.substr(start, end - start);
if (trim_token)
token = trim(token);
if (!token.empty()) {
tokens.push_back(token);
}
}
start = end + 1;
}

if (start < str.length()) {
std::string token = str.substr(start);
if (trim_token)
token = trim(token);
if (!token.empty()) {
tokens.push_back(token);
}
}

return tokens;
}

inline std::vector<std::string> split(const std::string& str, char delim) {
return split(str, delim, false);
}

inline std::vector<std::string> split_trim(const std::string& str, char delim) {
return split(str, delim, true);
}

template <typename T> T parse_number(std::string_view str) {

T id{};

auto [_, ec] = std::from_chars(str.data(), str.data() + str.size(), id);

if (ec != std::errc()) {
// note that this doesn't really make sense without understanding that
// "some_string".to_i = 0 in ruby
return {};
}
return id;
}

inline std::string escape(std::string_view input) {

int n = 0;
Expand Down
118 changes: 38 additions & 80 deletions src/api06/handler_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,112 +10,69 @@
#include "cgimap/api06/handler_utils.hpp"
#include "cgimap/http.hpp"
#include "cgimap/request_helpers.hpp"
#include "cgimap/util.hpp"

#include <algorithm>
#include <map>
#include <vector>
#include <string_view>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <fmt/core.h>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

using std::list;
using std::string;
using std::map;
using std::vector;
using std::pair;
namespace qi = boost::spirit::qi;
namespace standard = boost::spirit::standard;

BOOST_FUSION_ADAPT_STRUCT(
api06::id_version,
(uint64_t, id)
(std::optional<uint32_t>, version)
)

namespace {

template <typename Iterator>
struct id_version_parser : qi::grammar<Iterator, api06::id_version(), standard::space_type> {
id_version_parser() : id_version_parser::base_type(root) {
using qi::lit;
using qi::uint_;
using boost::spirit::ulong_long;

root = ulong_long >> -(lit("v") >> uint_);
}

qi::rule<Iterator, api06::id_version(), standard::space_type> root;
};
namespace api06 {

template <typename Iterator>
struct id_version_list_parser
: qi::grammar<Iterator, std::vector<api06::id_version>(), standard::space_type> {
id_version_list_parser() : id_version_list_parser::base_type(root) {
using qi::lit;

root = idv % lit(",");
}
// Helper function to parse a single id_version string like "123" or "123v2"
id_version parse_single_id(const std::string &str) {
id_version result{};

qi::rule<Iterator, std::vector<api06::id_version>(), standard::space_type> root;
id_version_parser<Iterator> idv;
};
// Split string at 'v'
std::vector<std::string> id_version = split(str, 'v');

} // anonymous namespace
switch (id_version.size()) {

namespace api06 {

bool valid_string(std::string_view str)
{
// check if character is representable as an unsigned char
// see https://www.boost.org/doc/libs/1_77_0/boost/spirit/home/support/char_encoding/standard.hpp
case 1:
// Just ID without version
result.id = parse_number<osm_nwr_id_t>(id_version[0]);
result.version = std::nullopt;
break;
case 2:
// ID with version
result.id = parse_number<osm_nwr_id_t>(id_version[0]);
result.version = parse_number<uint32_t>(id_version[1]);
break;
}

return std::all_of(str.begin(), str.end(),
[](uint8_t ch){ return ((ch & ~0x7f) == 0); });
return result;
}

vector<id_version> parse_id_list_params(const request &req, std::string_view param_name) {
std::vector<id_version> parse_id_list_params(const request &req,
std::string_view param_name) {

string decoded = http::urldecode(get_query_string(req));
const vector<pair<string, string> > params = http::parse_params(decoded);
auto itr = std::find_if(params.begin(), params.end(), [&param_name](auto& x){ return x.first == param_name; });
std::string decoded = http::urldecode(get_query_string(req));
const auto params = http::parse_params(decoded);

auto itr = std::find_if(params.begin(), params.end(), [&param_name](auto &x) {
return x.first == param_name;
});

if (itr == params.end())
return {};

const string &str = itr->second;
const std::string &str = itr->second;

if (str.empty())
return {};

// Make sure our string does not violate boost spirit standard encoding check in strict_ischar
// Failure to do so triggers assertion failures, unless NDEBUG flag is set during compilation.
if (!valid_string(str))
return {};

vector<id_version> parse_ids;
vector<id_version> myids;
string::const_iterator first = str.begin(), last = str.end();
id_version_list_parser<string::const_iterator> idv_p;
std::vector<id_version> myids;

try {
// Split the input string by commas
std::vector<std::string> id_strings = split(str, ',');

bool ok = qi::phrase_parse(
first, last, idv_p, boost::spirit::qi::standard::space, parse_ids);

if (ok && (first == last)) {
myids.swap(parse_ids);
} else {
myids.emplace_back(id_version());
// Parse each id_version string
for (const auto &id_str : id_strings) {
if (!id_str.empty()) {
myids.push_back(parse_single_id(id_str));
}
} catch (...) { // input could not be parsed, ignore
return {};
}

// ensure list of IDs is unique
Expand All @@ -125,4 +82,5 @@ vector<id_version> parse_id_list_params(const request &req, std::string_view par

return myids;
}
}

} // namespace api06
20 changes: 6 additions & 14 deletions src/bbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,9 @@
*/

#include "cgimap/bbox.hpp"
#include "cgimap/util.hpp"
#include <cmath>
#include <vector>
#include <boost/algorithm/string.hpp>

namespace al = boost::algorithm;

using std::string;
using std::max;
using std::min;
using std::vector;

bbox::bbox(double minlat_, double minlon_, double maxlat_, double maxlon_)
: minlat(minlat_), minlon(minlon_), maxlat(maxlat_), maxlon(maxlon_) {}
Expand All @@ -30,8 +23,7 @@ bool bbox::operator==(const bbox &other) const {
}

bool bbox::parse(const std::string &s) {
vector<string> strs;
al::split(strs, s, al::is_any_of(","));
const auto strs = split(s, ',');

if (strs.size() != 4)
return false;
Expand All @@ -53,10 +45,10 @@ bool bbox::parse(const std::string &s) {
}

void bbox::clip_to_world() {
minlon = max(minlon, -180.0);
minlat = max(minlat, -90.0);
maxlon = min(maxlon, 180.0);
maxlat = min(maxlat, 90.0);
minlon = std::max(minlon, -180.0);
minlat = std::max(minlat, -90.0);
maxlon = std::min(maxlon, 180.0);
maxlat = std::min(maxlat, 90.0);
}

bool bbox::valid() const {
Expand Down
Loading

0 comments on commit ba9f5d1

Please sign in to comment.