1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// This file is part of linux-support. It is subject to the license terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/linux-support/master/COPYRIGHT. No part of linux-support, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
// Copyright © 2021 The developers of linux-support. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/linux-support/master/COPYRIGHT.


/// Byte swap (change endian order of) an array of unaligned memory.
///
/// Byte swapping works irrespective of whether a value is signed or unsigned.
pub trait Unaligned: Debug + Copy + Eq + Ord + Hash
{
	#[doc(hidden)]
	#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "ssse3"))]
	const ShuffleControlMask128: [i8; BytesVector128Size];
	
	#[doc(hidden)]
	#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx", target_feature = "avx2"))]
	const ShuffleControlMask256: [i8; BytesVector256Size];
	
	#[doc(hidden)]
	#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx512f", target_feature = "avx512bw"))]
	const ShuffleControlMask512: [i8; BytesVector512Size];
	
	/// Converts from little endian to native endian.
	///
	/// Does nothing on a little endian CPU architecture.
	#[inline(always)]
	fn byte_swap_unaligned_memory_from_little_endian_to_native_endian(unaligned_memory: &mut [Self])
	{
		if cfg!(target_endian = "big")
		{
			Self::byte_swap_unaligned_memory(unaligned_memory)
		}
	}
	
	/// Converts from big endian to native endian.
	///
	/// Does nothing on a big endian CPU architecture.
	#[inline(always)]
	fn byte_swap_unaligned_memory_from_big_endian_to_native_endian(unaligned_memory: &mut [Self])
	{
		if cfg!(target_endian = "little")
		{
			Self::byte_swap_unaligned_memory(unaligned_memory)
		}
	}
	
	/// Byte swap unaligned memory.
	#[allow(unused_mut)]
	#[inline(always)]
	fn byte_swap_unaligned_memory(mut unaligned_memory: &mut [Self])
	{
		debug_assert_eq!(size_of::<Self>(), size_of::<Self::Aligned>());
		
		#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx512f", target_feature = "avx512bw"))]
		{
			unaligned_memory = BytesVector512::byte_swap_unaligned_memory::<Self>(unaligned_memory, Self::ShuffleControlMask512);
		}
		
		#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx", target_feature = "avx2"))]
		{
			unaligned_memory = BytesVector256::byte_swap_unaligned_memory::<Self>(unaligned_memory, Self::ShuffleControlMask256);
		}
		
		#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "ssse3"))]
		{
			unaligned_memory = BytesVector128::byte_swap_unaligned_memory::<Self>(unaligned_memory, Self::ShuffleControlMask128);
		}
		
		Self::swap_remaining_using_architecture_byte_swap_instruction(unaligned_memory)
	}
	
	/// Read an unaligned value and byte swap it before returning it.
	///
	/// May use `MOVBE`.
	#[inline(always)]
	fn read_unaligned_byte_swapped(aligned: NonNull<Self::Aligned>) -> Self::Aligned
	{
		let unaligned_reference = unsafe { & * (aligned.as_ptr() as *const Self) };
		unaligned_reference.load_and_swap_from_any_endian_bytes()
	}
	
	#[doc(hidden)]
	#[inline(always)]
	fn swap_remaining_using_architecture_byte_swap_instruction(unaligned_memory: &mut [Self])
	{
		for index in 0 .. unaligned_memory.len()
		{
			let unaligned = unaligned_memory.get_unchecked_mut_safe(index);
			unaligned.swap_using_architecture_byte_swap_instruction()
		}
	}
	
	#[doc(hidden)]
	#[inline(always)]
	fn swap_using_architecture_byte_swap_instruction(&mut self)
	{
		let aligned = self.load_and_swap_from_any_endian_bytes();
		*self = Self::into_any_endian_bytes(aligned)
	}
	
	#[doc(hidden)]
	type Aligned: Copy;
	
	#[doc(hidden)]
	fn load_and_swap_from_any_endian_bytes(&self) -> Self::Aligned;
	
	#[doc(hidden)]
	fn into_any_endian_bytes(aligned: Self::Aligned) -> Self;
	
	#[doc(hidden)]
	fn pointer(&self) -> *const Self::Aligned;
}