diff --git a/include/engine/api_response_generator.hpp b/include/engine/api_response_generator.hpp index cfdc5bdc1..0de8a7a24 100644 --- a/include/engine/api_response_generator.hpp +++ b/include/engine/api_response_generator.hpp @@ -277,10 +277,10 @@ ApiResponseGenerator::BuildHintData(const InternalRouteResult &raw_ std::string hint; for (const auto i : util::irange(0, raw_route.segment_end_coordinates.size())) { - ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint); - json_location_hint_array.values.push_back(hint); + hint = encodeBase64(raw_route.segment_end_coordinates[i].source_phantom); + json_location_hint_array.values.push_back(std::move(hint)); } - ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint); + hint = encodeBase64(raw_route.segment_end_coordinates.back().target_phantom); json_location_hint_array.values.emplace_back(std::move(hint)); json_hint_object.values["locations"] = json_location_hint_array; diff --git a/include/engine/object_encoder.hpp b/include/engine/object_encoder.hpp index c9fe21b04..496e8eadb 100644 --- a/include/engine/object_encoder.hpp +++ b/include/engine/object_encoder.hpp @@ -11,59 +11,75 @@ #include #include +#include +#include + namespace osrm { namespace engine { -struct ObjectEncoder +namespace detail { - using base64_t = boost::archive::iterators::base64_from_binary< - boost::archive::iterators::transform_width>; +static_assert(CHAR_BIT == 8u, "we assume a byte holds 8 bits"); +static_assert(sizeof(char) == 1u, "we assume a char is one byte large"); - using binary_t = boost::archive::iterators::transform_width< - boost::archive::iterators::binary_from_base64, - 8, - 6>; +using Base64FromBinary = boost::archive::iterators::base64_from_binary< + boost::archive::iterators::transform_width>; - template static void EncodeToBase64(const ObjectT &object, std::string &encoded) - { - const char *char_ptr_to_object = reinterpret_cast(&object); - std::vector data(sizeof(object)); - std::copy(char_ptr_to_object, char_ptr_to_object + sizeof(ObjectT), data.begin()); +using BinaryFromBase64 = boost::archive::iterators::transform_width< + boost::archive::iterators::binary_from_base64, + 8, // get a view of 8 bit + 6 // from a sequence of 6 bit + >; +} // ns detail - unsigned char number_of_padded_chars = 0; // is in {0,1,2}; - while (data.size() % 3 != 0) - { - ++number_of_padded_chars; - data.push_back(0x00); - } +template std::string encodeBase64(const T &x) +{ + // static_assert(std::is_trivially_copyable::value, "requires a trivially copyable type"); - BOOST_ASSERT_MSG(0 == data.size() % 3, "base64 input data size is not a multiple of 3!"); - encoded.resize(sizeof(ObjectT)); - encoded.assign(base64_t(&data[0]), - base64_t(&data[0] + (data.size() - number_of_padded_chars))); - std::replace(begin(encoded), end(encoded), '+', '-'); - std::replace(begin(encoded), end(encoded), '/', '_'); - } + std::vector bytes{reinterpret_cast(&x), + reinterpret_cast(&x) + sizeof(T)}; + BOOST_ASSERT(!bytes.empty()); - template static void DecodeFromBase64(const std::string &input, ObjectT &object) - { - try - { - std::string encoded(input); - std::replace(begin(encoded), end(encoded), '-', '+'); - std::replace(begin(encoded), end(encoded), '_', '/'); + const auto next_divisible_by_three = ((bytes.size() / 3u) + 1u) * 3u; + BOOST_ASSERT(next_divisible_by_three >= bytes.size()); - std::copy(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length()), - reinterpret_cast(&object)); - } - catch (...) - { - } - } -}; + const auto bytes_to_pad = next_divisible_by_three - bytes.size(); + BOOST_ASSERT(bytes_to_pad == 0 || bytes_to_pad == 1 || bytes_to_pad == 2); + + bytes.insert(end(bytes), bytes_to_pad, 0x00); + BOOST_ASSERT_MSG(0 == bytes.size() % 3, "base64 input data size is not a multiple of 3"); + + std::string encoded{detail::Base64FromBinary{bytes.data()}, + detail::Base64FromBinary{bytes.data() + (bytes.size() - bytes_to_pad)}}; + + std::replace(begin(encoded), end(encoded), '+', '-'); + std::replace(begin(encoded), end(encoded), '/', '_'); + + return encoded; } + +template T decodeBase64(std::string encoded) +{ + // static_assert(std::is_trivially_copyable::value, "requires a trivially copyable type"); + + std::replace(begin(encoded), end(encoded), '-', '+'); + std::replace(begin(encoded), end(encoded), '_', '/'); + + T rv; + + std::copy(detail::BinaryFromBase64{begin(encoded)}, + detail::BinaryFromBase64{begin(encoded) + encoded.length()}, + reinterpret_cast(&rv)); + + return rv; } +} // ns engine +} // ns osrm + #endif /* OBJECT_ENCODER_HPP */ diff --git a/include/engine/plugins/distance_table.hpp b/include/engine/plugins/distance_table.hpp index b1625ed93..1c6d5093f 100644 --- a/include/engine/plugins/distance_table.hpp +++ b/include/engine/plugins/distance_table.hpp @@ -94,8 +94,7 @@ template class DistanceTablePlugin final : public BasePlugin if (checksum_OK && i < route_parameters.hints.size() && !route_parameters.hints[i].empty()) { - PhantomNode current_phantom_node; - ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node); + auto current_phantom_node = decodeBase64(route_parameters.hints[i]); if (current_phantom_node.IsValid(facade->GetNumberOfNodes())) { if (route_parameters.is_source[i]) diff --git a/include/engine/plugins/trip.hpp b/include/engine/plugins/trip.hpp index db8440547..35abce2cb 100644 --- a/include/engine/plugins/trip.hpp +++ b/include/engine/plugins/trip.hpp @@ -64,8 +64,7 @@ template class RoundTripPlugin final : public BasePlugin if (checksum_OK && i < route_parameters.hints.size() && !route_parameters.hints[i].empty()) { - PhantomNode current_phantom_node; - ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node); + auto current_phantom_node = decodeBase64(route_parameters.hints[i]); if (current_phantom_node.IsValid(facade->GetNumberOfNodes())) { phantom_node_list.push_back(std::move(current_phantom_node)); @@ -317,7 +316,6 @@ template class RoundTripPlugin final : public BasePlugin // } // return s; // }(); - } else { diff --git a/include/engine/plugins/viaroute.hpp b/include/engine/plugins/viaroute.hpp index f34ddc675..fe041dd5c 100644 --- a/include/engine/plugins/viaroute.hpp +++ b/include/engine/plugins/viaroute.hpp @@ -83,8 +83,8 @@ template class ViaRoutePlugin final : public BasePlugin if (checksum_OK && i < route_parameters.hints.size() && !route_parameters.hints[i].empty()) { - ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], - phantom_node_pair_list[i].first); + phantom_node_pair_list[i].first = + decodeBase64(route_parameters.hints[i]); if (phantom_node_pair_list[i].first.IsValid(facade->GetNumberOfNodes())) { continue; @@ -111,8 +111,8 @@ template class ViaRoutePlugin final : public BasePlugin auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list); InternalRouteResult raw_route; - auto build_phantom_pairs = [&raw_route](const PhantomNode &first_node, - const PhantomNode &second_node) + auto build_phantom_pairs = + [&raw_route](const PhantomNode &first_node, const PhantomNode &second_node) { raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node}); };