Refactors Base64 encoding and decoding, it's almost beautiful now
This commit is contained in:
parent
ec01c2a119
commit
aac21f932b
@ -277,10 +277,10 @@ ApiResponseGenerator<DataFacadeT>::BuildHintData(const InternalRouteResult &raw_
|
||||
std::string hint;
|
||||
for (const auto i : util::irange<std::size_t>(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;
|
||||
|
||||
|
@ -11,59 +11,75 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cstdint>
|
||||
#include <climits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
|
||||
struct ObjectEncoder
|
||||
namespace detail
|
||||
{
|
||||
using base64_t = boost::archive::iterators::base64_from_binary<
|
||||
boost::archive::iterators::transform_width<const char *, 6, 8>>;
|
||||
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<
|
||||
using Base64FromBinary = boost::archive::iterators::base64_from_binary<
|
||||
boost::archive::iterators::transform_width<const char *, // sequence of chars
|
||||
6, // get view of 6 bit
|
||||
8 // from sequence of 8 bit
|
||||
>>;
|
||||
|
||||
using BinaryFromBase64 = boost::archive::iterators::transform_width<
|
||||
boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
|
||||
8,
|
||||
6>;
|
||||
8, // get a view of 8 bit
|
||||
6 // from a sequence of 6 bit
|
||||
>;
|
||||
} // ns detail
|
||||
|
||||
template <class ObjectT> static void EncodeToBase64(const ObjectT &object, std::string &encoded)
|
||||
{
|
||||
const char *char_ptr_to_object = reinterpret_cast<const char *>(&object);
|
||||
std::vector<unsigned char> data(sizeof(object));
|
||||
std::copy(char_ptr_to_object, char_ptr_to_object + sizeof(ObjectT), data.begin());
|
||||
template <typename T> std::string encodeBase64(const T &x)
|
||||
{
|
||||
// static_assert(std::is_trivially_copyable<T>::value, "requires a trivially copyable type");
|
||||
|
||||
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);
|
||||
}
|
||||
std::vector<unsigned char> bytes{reinterpret_cast<const char *>(&x),
|
||||
reinterpret_cast<const char *>(&x) + sizeof(T)};
|
||||
BOOST_ASSERT(!bytes.empty());
|
||||
|
||||
const auto next_divisible_by_three = ((bytes.size() / 3u) + 1u) * 3u;
|
||||
BOOST_ASSERT(next_divisible_by_three >= bytes.size());
|
||||
|
||||
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)}};
|
||||
|
||||
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), '/', '_');
|
||||
}
|
||||
|
||||
template <class ObjectT> static void DecodeFromBase64(const std::string &input, ObjectT &object)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string encoded(input);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
template <typename T> T decodeBase64(std::string encoded)
|
||||
{
|
||||
// static_assert(std::is_trivially_copyable<T>::value, "requires a trivially copyable type");
|
||||
|
||||
std::replace(begin(encoded), end(encoded), '-', '+');
|
||||
std::replace(begin(encoded), end(encoded), '_', '/');
|
||||
|
||||
std::copy(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length()),
|
||||
reinterpret_cast<char *>(&object));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
T rv;
|
||||
|
||||
std::copy(detail::BinaryFromBase64{begin(encoded)},
|
||||
detail::BinaryFromBase64{begin(encoded) + encoded.length()},
|
||||
reinterpret_cast<char *>(&rv));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // ns engine
|
||||
} // ns osrm
|
||||
|
||||
#endif /* OBJECT_ENCODER_HPP */
|
||||
|
@ -94,8 +94,7 @@ template <class DataFacadeT> 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<PhantomNode>(route_parameters.hints[i]);
|
||||
if (current_phantom_node.IsValid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
if (route_parameters.is_source[i])
|
||||
|
@ -64,8 +64,7 @@ template <class DataFacadeT> 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<PhantomNode>(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 DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
// }
|
||||
// return s;
|
||||
// }();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -83,8 +83,8 @@ template <class DataFacadeT> 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<PhantomNode>(route_parameters.hints[i]);
|
||||
if (phantom_node_pair_list[i].first.IsValid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
continue;
|
||||
@ -111,8 +111,8 @@ template <class DataFacadeT> 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});
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user