One Motor 0.6.0
RoboMaster全平台一站式电机驱动库
载入中...
搜索中...
未找到
DoubleBuffer.hpp
浏览该文件的文档.
1#ifndef ONEMOTOR_DOUBLEBUFFER_HPP
2#define ONEMOTOR_DOUBLEBUFFER_HPP
3
4#include <cstring>
5#include <atomic>
6#include <array>
7#include <utility>
8
16
17
18namespace OneMotor
19{
20 template <typename T>
21 class DoubleBuffer
22 {
23 public:
24 DoubleBuffer() noexcept
25 {
26 static_assert(std::is_default_constructible_v<T>,
27 "T must be default constructible for DoubleBuffer default ctor");
28 m_Buffers[0] = T();
29 m_Buffers[1] = T();
30 m_CurrentRead.store(&m_Buffers[0], std::memory_order_release);
31 m_CurrentWrite = &m_Buffers[1];
32 }
33
34 template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
35 explicit DoubleBuffer(Args&&... args)
36 {
37 m_Buffers = std::array<T, 2>{T(std::forward<Args>(args)...), T(std::forward<Args>(args)...)};
38 m_CurrentRead.store(&m_Buffers[0], std::memory_order_release);
39 m_CurrentWrite = &m_Buffers[1];
40 }
41
42 // 禁用拷贝语义
43 DoubleBuffer(const DoubleBuffer&) = delete;
44 DoubleBuffer& operator=(const DoubleBuffer&) = delete;
45
46 // 移动语义,保证内部原子指针指向新对象的缓冲区
47 DoubleBuffer(DoubleBuffer&& other) noexcept
48 {
49 m_Buffers = std::move(other.m_Buffers);
50
51 T* other_read = other.m_CurrentRead.load(std::memory_order_acquire);
52 std::size_t idx = 0;
53 if (other_read == &other.m_Buffers[0]) idx = 0;
54 else if (other_read == &other.m_Buffers[1]) idx = 1;
55 else idx = 0; // 保守处理(应当不会发生)
56
57 m_CurrentRead.store(&m_Buffers[idx], std::memory_order_release);
58 m_CurrentWrite = &m_Buffers[1 - idx];
59
60 // 留下被移动对象为有效状态
61 other.m_CurrentRead.store(&other.m_Buffers[0], std::memory_order_release);
62 other.m_CurrentWrite = &other.m_Buffers[1];
63 }
64
65 DoubleBuffer& operator=(DoubleBuffer&& other) noexcept
66 {
67 if (this == &other) return *this;
68
69 m_Buffers = std::move(other.m_Buffers);
70
71 T* other_read = other.m_CurrentRead.load(std::memory_order_acquire);
72 std::size_t idx = 0;
73 if (other_read == &other.m_Buffers[0]) idx = 0;
74 else if (other_read == &other.m_Buffers[1]) idx = 1;
75 else idx = 0;
76
77 m_CurrentRead.store(&m_Buffers[idx], std::memory_order_release);
78 m_CurrentWrite = &m_Buffers[1 - idx];
79
80 other.m_CurrentRead.store(&other.m_Buffers[0], std::memory_order_release);
81 other.m_CurrentWrite = &other.m_Buffers[1];
82
83 return *this;
84 }
85
86 const T& readView() noexcept
87 {
88 return *m_CurrentRead.load(std::memory_order_acquire);
89 }
90
91 T readCopy() noexcept
92 {
93 return *m_CurrentRead.load(std::memory_order_acquire);
94 }
95
96 T& write() noexcept
97 {
98 return *m_CurrentWrite;
99 }
100
101 void swap() noexcept
102 {
103 T* old_read = m_CurrentRead.exchange(m_CurrentWrite, std::memory_order_acq_rel);
104 m_CurrentWrite = old_read;
105 }
106
107 void push(const T& frame) noexcept
108 {
109 std::memcpy(m_CurrentWrite, &frame, sizeof(T));
110 swap();
111 }
112
113 private:
114 std::array<T, 2> m_Buffers;
115
116 std::atomic<T*> m_CurrentRead{nullptr};
117 T* m_CurrentWrite{nullptr};
118 };
119}
120
121#endif //ONEMOTOR_DOUBLEBUFFER_HPP