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;
|
std::string hint;
|
||||||
for (const auto i : util::irange<std::size_t>(0, raw_route.segment_end_coordinates.size()))
|
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);
|
hint = encodeBase64(raw_route.segment_end_coordinates[i].source_phantom);
|
||||||
json_location_hint_array.values.push_back(hint);
|
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_location_hint_array.values.emplace_back(std::move(hint));
|
||||||
json_hint_object.values["locations"] = json_location_hint_array;
|
json_hint_object.values["locations"] = json_location_hint_array;
|
||||||
|
|
||||||
|
@ -11,59 +11,75 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace engine
|
namespace engine
|
||||||
{
|
{
|
||||||
|
|
||||||
struct ObjectEncoder
|
namespace detail
|
||||||
{
|
{
|
||||||
using base64_t = boost::archive::iterators::base64_from_binary<
|
static_assert(CHAR_BIT == 8u, "we assume a byte holds 8 bits");
|
||||||
boost::archive::iterators::transform_width<const char *, 6, 8>>;
|
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::binary_from_base64<std::string::const_iterator>,
|
boost::archive::iterators::transform_width<const char *, // sequence of chars
|
||||||
8,
|
6, // get view of 6 bit
|
||||||
6>;
|
8 // from sequence of 8 bit
|
||||||
|
>>;
|
||||||
|
|
||||||
template <class ObjectT> static void EncodeToBase64(const ObjectT &object, std::string &encoded)
|
using BinaryFromBase64 = boost::archive::iterators::transform_width<
|
||||||
{
|
boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
|
||||||
const char *char_ptr_to_object = reinterpret_cast<const char *>(&object);
|
8, // get a view of 8 bit
|
||||||
std::vector<unsigned char> data(sizeof(object));
|
6 // from a sequence of 6 bit
|
||||||
std::copy(char_ptr_to_object, char_ptr_to_object + sizeof(ObjectT), data.begin());
|
>;
|
||||||
|
} // ns detail
|
||||||
|
|
||||||
unsigned char number_of_padded_chars = 0; // is in {0,1,2};
|
template <typename T> std::string encodeBase64(const T &x)
|
||||||
while (data.size() % 3 != 0)
|
{
|
||||||
{
|
// static_assert(std::is_trivially_copyable<T>::value, "requires a trivially copyable type");
|
||||||
++number_of_padded_chars;
|
|
||||||
data.push_back(0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_ASSERT_MSG(0 == data.size() % 3, "base64 input data size is not a multiple of 3!");
|
std::vector<unsigned char> bytes{reinterpret_cast<const char *>(&x),
|
||||||
encoded.resize(sizeof(ObjectT));
|
reinterpret_cast<const char *>(&x) + sizeof(T)};
|
||||||
encoded.assign(base64_t(&data[0]),
|
BOOST_ASSERT(!bytes.empty());
|
||||||
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)
|
const auto next_divisible_by_three = ((bytes.size() / 3u) + 1u) * 3u;
|
||||||
{
|
BOOST_ASSERT(next_divisible_by_three >= bytes.size());
|
||||||
try
|
|
||||||
{
|
|
||||||
std::string encoded(input);
|
|
||||||
std::replace(begin(encoded), end(encoded), '-', '+');
|
|
||||||
std::replace(begin(encoded), end(encoded), '_', '/');
|
|
||||||
|
|
||||||
std::copy(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length()),
|
const auto bytes_to_pad = next_divisible_by_three - bytes.size();
|
||||||
reinterpret_cast<char *>(&object));
|
BOOST_ASSERT(bytes_to_pad == 0 || bytes_to_pad == 1 || bytes_to_pad == 2);
|
||||||
}
|
|
||||||
catch (...)
|
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 <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), '_', '/');
|
||||||
|
|
||||||
|
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 */
|
#endif /* OBJECT_ENCODER_HPP */
|
||||||
|
@ -94,8 +94,7 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
|
|||||||
if (checksum_OK && i < route_parameters.hints.size() &&
|
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||||
!route_parameters.hints[i].empty())
|
!route_parameters.hints[i].empty())
|
||||||
{
|
{
|
||||||
PhantomNode current_phantom_node;
|
auto current_phantom_node = decodeBase64<PhantomNode>(route_parameters.hints[i]);
|
||||||
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
|
|
||||||
if (current_phantom_node.IsValid(facade->GetNumberOfNodes()))
|
if (current_phantom_node.IsValid(facade->GetNumberOfNodes()))
|
||||||
{
|
{
|
||||||
if (route_parameters.is_source[i])
|
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() &&
|
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||||
!route_parameters.hints[i].empty())
|
!route_parameters.hints[i].empty())
|
||||||
{
|
{
|
||||||
PhantomNode current_phantom_node;
|
auto current_phantom_node = decodeBase64<PhantomNode>(route_parameters.hints[i]);
|
||||||
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
|
|
||||||
if (current_phantom_node.IsValid(facade->GetNumberOfNodes()))
|
if (current_phantom_node.IsValid(facade->GetNumberOfNodes()))
|
||||||
{
|
{
|
||||||
phantom_node_list.push_back(std::move(current_phantom_node));
|
phantom_node_list.push_back(std::move(current_phantom_node));
|
||||||
@ -317,7 +316,6 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
|||||||
// }
|
// }
|
||||||
// return s;
|
// return s;
|
||||||
// }();
|
// }();
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -83,8 +83,8 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
|||||||
if (checksum_OK && i < route_parameters.hints.size() &&
|
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||||
!route_parameters.hints[i].empty())
|
!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()))
|
if (phantom_node_pair_list[i].first.IsValid(facade->GetNumberOfNodes()))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -111,8 +111,8 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
|||||||
auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list);
|
auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list);
|
||||||
|
|
||||||
InternalRouteResult raw_route;
|
InternalRouteResult raw_route;
|
||||||
auto build_phantom_pairs = [&raw_route](const PhantomNode &first_node,
|
auto build_phantom_pairs =
|
||||||
const PhantomNode &second_node)
|
[&raw_route](const PhantomNode &first_node, const PhantomNode &second_node)
|
||||||
{
|
{
|
||||||
raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
|
raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user