@@ -119,6 +119,20 @@ namespace xt
119119 using type = T;
120120 };
121121
122+ /* **************************************
123+ * is_specialization_of implementation *
124+ ***************************************/
125+
126+ template <template <class ...> class TT , class T >
127+ struct is_specialization_of : std::false_type
128+ {
129+ };
130+
131+ template <template <class ...> class TT , class ... Ts>
132+ struct is_specialization_of <TT, TT<Ts...>> : std::true_type
133+ {
134+ };
135+
122136 /* ******************************
123137 * remove_class implementation *
124138 *******************************/
@@ -860,6 +874,139 @@ namespace xt
860874 {
861875 };
862876
877+ /* ************************************
878+ * overlapping_memory_checker_traits *
879+ *************************************/
880+
881+ template <class T , class Enable = void >
882+ struct has_memory_address : std::false_type
883+ {
884+ };
885+
886+ template <class T >
887+ struct has_memory_address <T, void_t <decltype (std::addressof(*std::declval<T>().begin()))>> : std::true_type
888+ {
889+ };
890+
891+ struct memory_range
892+ {
893+ // Checking pointer overlap is more correct in integer values,
894+ // for more explanation check https://devblogs.microsoft.com/oldnewthing/20170927-00/?p=97095
895+ const uintptr_t m_first = 0 ;
896+ const uintptr_t m_last = 0 ;
897+
898+ explicit memory_range () = default;
899+
900+ template <class T >
901+ explicit memory_range (T* first, T* last)
902+ : m_first(reinterpret_cast <uintptr_t >(last < first ? last : first))
903+ , m_last(reinterpret_cast <uintptr_t >(last < first ? first : last))
904+ {
905+ }
906+
907+ template <class T >
908+ bool overlaps (T* first, T* last) const
909+ {
910+ if (first <= last)
911+ {
912+ return reinterpret_cast <uintptr_t >(first) <= m_last
913+ && reinterpret_cast <uintptr_t >(last) >= m_first;
914+ }
915+ else
916+ {
917+ return reinterpret_cast <uintptr_t >(last) <= m_last
918+ && reinterpret_cast <uintptr_t >(first) >= m_first;
919+ }
920+ }
921+ };
922+
923+ template <class E , class Enable = void >
924+ struct overlapping_memory_checker_traits
925+ {
926+ static bool check_overlap (const E&, const memory_range&)
927+ {
928+ return true ;
929+ }
930+ };
931+
932+ template <class E >
933+ struct overlapping_memory_checker_traits <E, std::enable_if_t <has_memory_address<E>::value>>
934+ {
935+ static bool check_overlap (const E& expr, const memory_range& dst_range)
936+ {
937+ if (expr.size () == 0 )
938+ {
939+ return false ;
940+ }
941+ else
942+ {
943+ return dst_range.overlaps (std::addressof (*expr.begin ()), std::addressof (*expr.rbegin ()));
944+ }
945+ }
946+ };
947+
948+ struct overlapping_memory_checker_base
949+ {
950+ memory_range m_dst_range;
951+
952+ explicit overlapping_memory_checker_base () = default;
953+
954+ explicit overlapping_memory_checker_base (memory_range dst_memory_range)
955+ : m_dst_range(std::move(dst_memory_range))
956+ {
957+ }
958+
959+ template <class E >
960+ bool check_overlap (const E& expr) const
961+ {
962+ if (!m_dst_range.m_first || !m_dst_range.m_last )
963+ {
964+ return false ;
965+ }
966+ else
967+ {
968+ return overlapping_memory_checker_traits<E>::check_overlap (expr, m_dst_range);
969+ }
970+ }
971+ };
972+
973+ template <class Dst , class Enable = void >
974+ struct overlapping_memory_checker : overlapping_memory_checker_base
975+ {
976+ explicit overlapping_memory_checker (const Dst&)
977+ : overlapping_memory_checker_base()
978+ {
979+ }
980+ };
981+
982+ template <class Dst >
983+ struct overlapping_memory_checker <Dst, std::enable_if_t <has_memory_address<Dst>::value>>
984+ : overlapping_memory_checker_base
985+ {
986+ explicit overlapping_memory_checker (const Dst& aDst)
987+ : overlapping_memory_checker_base(
988+ [&]()
989+ {
990+ if (aDst.size () == 0 )
991+ {
992+ return memory_range ();
993+ }
994+ else
995+ {
996+ return memory_range (std::addressof (*aDst.begin ()), std::addressof (*aDst.rbegin ()));
997+ }
998+ }()
999+ )
1000+ {
1001+ }
1002+ };
1003+
1004+ template <class Dst >
1005+ auto make_overlapping_memory_checker (const Dst& a_dst)
1006+ {
1007+ return overlapping_memory_checker<Dst>(a_dst);
1008+ }
1009+
8631010 /* *******************
8641011 * rebind_container *
8651012 ********************/
0 commit comments