simdutf 8.0.0
Unicode at GB/s.
Loading...
Searching...
No Matches
atomic_util.h
1#ifndef SIMDUTF_ATOMIC_UTIL_H
2#define SIMDUTF_ATOMIC_UTIL_H
3#if SIMDUTF_ATOMIC_REF
4 #include <atomic>
5namespace simdutf {
6namespace scalar {
7
8// This function is a memcpy that uses atomic operations to read from the
9// source.
10inline void memcpy_atomic_read(char *dst, const char *src, size_t len) {
11 static_assert(std::atomic_ref<char>::required_alignment == sizeof(char),
12 "std::atomic_ref requires the same alignment as char_type");
13 // We expect all 64-bit systems to be able to read 64-bit words from an
14 // aligned memory region atomically. You might be able to do better on
15 // specific systems, e.g., x64 systems can read 128-bit words atomically.
16 constexpr size_t alignment = sizeof(uint64_t);
17
18 // Lambda for atomic byte-by-byte copy
19 auto bbb_memcpy_atomic_read = [](char *bytedst, const char *bytesrc,
20 size_t bytelen) noexcept {
21 char *mutable_src = const_cast<char *>(bytesrc);
22 for (size_t j = 0; j < bytelen; ++j) {
23 bytedst[j] =
24 std::atomic_ref<char>(mutable_src[j]).load(std::memory_order_relaxed);
25 }
26 };
27
28 // Handle unaligned start
29 size_t offset = reinterpret_cast<std::uintptr_t>(src) % alignment;
30 if (offset) {
31 size_t to_align = std::min(len, alignment - offset);
32 bbb_memcpy_atomic_read(dst, src, to_align);
33 src += to_align;
34 dst += to_align;
35 len -= to_align;
36 }
37
38 // Process aligned 64-bit chunks
39 while (len >= alignment) {
40 auto *src_aligned = reinterpret_cast<uint64_t *>(const_cast<char *>(src));
41 const auto dst_value =
42 std::atomic_ref<uint64_t>(*src_aligned).load(std::memory_order_relaxed);
43 std::memcpy(dst, &dst_value, sizeof(uint64_t));
44 src += alignment;
45 dst += alignment;
46 len -= alignment;
47 }
48
49 // Handle remaining bytes
50 if (len) {
51 bbb_memcpy_atomic_read(dst, src, len);
52 }
53}
54
55// This function is a memcpy that uses atomic operations to write to the
56// destination.
57inline void memcpy_atomic_write(char *dst, const char *src, size_t len) {
58 static_assert(std::atomic_ref<char>::required_alignment == sizeof(char),
59 "std::atomic_ref requires the same alignment as char");
60 // We expect all 64-bit systems to be able to write 64-bit words to an aligned
61 // memory region atomically.
62 // You might be able to do better on specific systems, e.g., x64 systems can
63 // write 128-bit words atomically.
64 constexpr size_t alignment = sizeof(uint64_t);
65
66 // Lambda for atomic byte-by-byte write
67 auto bbb_memcpy_atomic_write = [](char *bytedst, const char *bytesrc,
68 size_t bytelen) noexcept {
69 for (size_t j = 0; j < bytelen; ++j) {
70 std::atomic_ref<char>(bytedst[j])
71 .store(bytesrc[j], std::memory_order_relaxed);
72 }
73 };
74
75 // Handle unaligned start
76 size_t offset = reinterpret_cast<std::uintptr_t>(dst) % alignment;
77 if (offset) {
78 size_t to_align = std::min(len, alignment - offset);
79 bbb_memcpy_atomic_write(dst, src, to_align);
80 dst += to_align;
81 src += to_align;
82 len -= to_align;
83 }
84
85 // Process aligned 64-bit chunks
86 while (len >= alignment) {
87 auto *dst_aligned = reinterpret_cast<uint64_t *>(dst);
88 uint64_t src_val;
89 std::memcpy(&src_val, src, sizeof(uint64_t)); // Non-atomic read from src
90 std::atomic_ref<uint64_t>(*dst_aligned)
91 .store(src_val, std::memory_order_relaxed);
92 dst += alignment;
93 src += alignment;
94 len -= alignment;
95 }
96
97 // Handle remaining bytes
98 if (len) {
99 bbb_memcpy_atomic_write(dst, src, len);
100 }
101}
102} // namespace scalar
103} // namespace simdutf
104#endif // SIMDUTF_ATOMIC_REF
105#endif // SIMDUTF_ATOMIC_UTIL_H