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