From c6c7498562a47d80ebcbabba3e714ee37d2ca9c0 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Thu, 25 Apr 2024 12:41:08 +0200 Subject: [PATCH] mapping: add dst2src and src2dst Signed-off-by: Simon Rozman --- include/stdex/mapping.hpp | 165 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/include/stdex/mapping.hpp b/include/stdex/mapping.hpp index 048f17c65..6f13cfca7 100644 --- a/include/stdex/mapping.hpp +++ b/include/stdex/mapping.hpp @@ -6,6 +6,7 @@ #pragma once #include "compat.hpp" +#include #include namespace stdex @@ -71,4 +72,168 @@ namespace stdex template >> using mapping_vector = std::vector, AX>; + + /// + /// Transforms destination index to source index + /// + /// \param[in] mapping Ordered vector of source to destination mappings + /// \param[in] to Index in destination string + /// + /// \returns Index in source string + /// + template >> + T dst2src(_In_ const std::vector, AX>& mapping, _In_ T to) + { + if (mapping.empty()) + return to; + + for (size_t l = 0, r = mapping.size();;) { + if (l < r) { + auto m = (l + r) / 2; + const auto& el = mapping[m]; + if (to < el.to) r = m; + else if (el.to < to) l = m + 1; + else return el.from; + } + else if (l) { + const auto& el = mapping[l - 1]; + return el.from + (to - el.to); + } + else { + const auto& el = mapping[0]; + return std::min(to, el.from); + } + } + } + + /// + /// Transforms destination index to source index + /// + /// \param[in] mapping Ordered vector of source to destination mappings + /// \param[in] to Index in destination string + /// \param[in,out] m Hint to speed-up bisection when calling this function in a loop and successive destination string indexes are in vicinity. Initialize to 0. + /// + /// \returns Index in source string + /// + template >> + T dst2src(_In_ const std::vector, AX>& mapping, _In_ T to, _Inout_opt_ size_t& m) + { + if (mapping.empty()) + return to; + + size_t l, r; + const auto& el = mapping[m]; + if (to < el.to) { + l = 0; + r = m; + } + else if (el.to < to) { + if (mapping.size() - 1 <= m || to < mapping[m + 1].to) + return el.from + (to - el.to); + l = m + 1; + r = mapping.size(); + } + else + return el.from; + + for (;;) { + if (l < r) { + m = (l + r) / 2; + const auto& el = mapping[m]; + if (to < el.to) r = m; + else if (el.to < to) l = m + 1; + else return el.from; + } + else if (l) { + const auto& el = mapping[m = l - 1]; + return el.from + (to - el.to); + } + else { + const auto& el = mapping[m = 0]; + return std::min(to, el.from); + } + } + } + + /// + /// Transforms source index to destination index + /// + /// \param[in] mapping Ordered vector of source to destination mappings + /// \param[in] from Index in source string + /// + /// \returns Index in destination string + /// + template >> + T src2dst(_In_ const std::vector, AX>& mapping, _In_ T from) + { + if (mapping.empty()) + return from; + + for (size_t l = 0, r = mapping.size();;) { + if (l < r) { + auto m = (l + r) / 2; + const auto& el = mapping[m]; + if (from < el.from) r = m; + else if (el.from < from) l = m + 1; + else return el.to; + } + else if (l) { + const auto& el = mapping[l - 1]; + return el.to + (from - el.from); + } + else { + const auto& el = mapping[0]; + return std::min(from, el.to); + } + } + } + + /// + /// Transforms source index to destination index + /// + /// \param[in] mapping Ordered vector of source to destination mappings + /// \param[in] from Index in source string + /// \param[in,out] m Hint to speed-up bisection when calling this function in a loop and successive source string indexes are in vicinity. Initialize to 0. + /// + /// \returns Index in destination string + /// + template >> + T src2dst(_In_ const std::vector, AX>& mapping, _In_ T from, _Inout_opt_ size_t& m) + { + if (mapping.empty()) + return from; + + size_t l, r; + const auto& el = mapping[m]; + if (from < el.from) { + l = 0; + r = m; + } + else if (el.from < from) { + if (mapping.size() - 1 <= m || from < mapping[m + 1].from) + return el.to + (from - el.from); + l = m + 1; + r = mapping.size(); + } + else + return el.to; + + for (;;) { + if (l < r) { + m = (l + r) / 2; + const auto& el = mapping[m]; + if (from < el.from) r = m; + else if (el.from < from) l = m + 1; + else return el.to; + } + else if (l) { + const auto& el = mapping[m = l - 1]; + return el.to + (from - el.from); + } + else { + const auto& el = mapping[m = 0]; + return std::min(from, el.to); + } + } + } }