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