fast_able/
stock_pool.rs

1use std::{
2    cell::UnsafeCell,
3    ops::{Index, IndexMut},
4};
5
6/// Design a high-performance stock pool, where all data is stored in arrays, and data is accessed via array indices; this index is converted from the stock code;
7/// 4 arrays, one for Shanghai Main Board stocks, one for Shenzhen Main Board stocks, one for ChiNext stocks; and one for STAR Market stocks;
8/// The length of each array is fixed, determined by the number of stocks in the A-share market; for example, if the number of Shanghai Main Board stocks is 1500, the array length is 1500;
9///
10/// 设计一个高性能股票池, 数据全部以数组的形式存储, 通过数组的下标来获取数据; 此下标是股票代码转换而来;
11/// 4个数组, 一个存储上海主板股票, 一个存储深圳主板股票, 一个存储创业板股票; 还有一个数组存储科创板股票;
12/// 每个数组的长度是固定的, 都根据A股市场的股票数量来确定; 例如上海主板股票数量是1500, 则数组的长度是1500;
13pub struct StockPool<T> {
14    stock_list: [Vec<UnsafeCell<Option<Box<T>>>>; 10],
15}
16
17impl<T: Default> StockPool<T> {
18
19    /// Create a new StockPool with default values
20    /// 创建一个带有默认值的 StockPool
21    #[must_use]
22    pub fn new_default() -> StockPool<T> {
23        let get = || {
24            let mut add_v = Vec::with_capacity(10_0000);
25            for _ in 0..10_0000 {
26                add_v.push(UnsafeCell::new(Some(Box::new(T::default()))));
27            }
28            add_v
29        };
30        StockPool {
31            stock_list: [
32                get(),
33                get(),
34                get(),
35                get(),
36                get(),
37                get(),
38                get(),
39                get(),
40                get(),
41                get(),
42            ],
43        }
44    }
45}
46
47impl<T> StockPool<T> {
48    // Initialize stock pool; calling this method requires calling insert method to insert data;
49    // 初始化股票池; 调用此方法则必须调用insert方法来插入数据;
50    #[must_use]
51    pub fn new_empty() -> StockPool<T> {
52        let get = || {
53            let mut add_v = Vec::with_capacity(10_0000);
54            for _ in 0..10_0000 {
55                add_v.push(UnsafeCell::new(None));
56            }
57            add_v
58        };
59        StockPool {
60            stock_list: [
61                get(),
62                get(),
63                get(),
64                get(),
65                get(),
66                get(),
67                get(),
68                get(),
69                get(),
70                get(),
71            ],
72        }
73    }
74
75    /// Get the number of items in the pool
76    /// 获取池中的项目数量
77    #[must_use]
78    pub fn len(&self) -> usize {
79        self.all_items().len()
80    }
81
82    #[inline(always)]
83    fn _get<'a>(&'a self, i7: i32) -> &'a mut Option<Box<T>> {
84        // 高性能写法
85        let i7 = i7 as usize;
86        let i6 = i7 % 1_000_000;
87        let i = i6 / 1000_00;
88        let i5 = i6 % 1000_00;
89        let r = &self.stock_list[i]
90            .get(i5)
91            .unwrap_or_else(|| unreachable!("股票代码在股票池中不存在: {i7}({i}-{i5})"));
92        unsafe { &mut *r.get() }
93    }
94
95    /// Get all items in the pool
96    /// 获取池中的所有项目
97    pub fn all_items(&self) -> Vec<&T> {
98        let mut items = Vec::new();
99        for ele in self.stock_list.iter() {
100            for ele in ele {
101                if let Some(item) = unsafe { &*ele.get() } {
102                    items.push(item.as_ref());
103                }
104            }
105        }
106
107        items
108    }
109
110    /// Check if the item at the given index is empty
111    /// 检查给定索引处的项目是否为空
112    #[inline(always)]
113    pub fn is_empty(&self, i7: i32) -> bool {
114        self._get(i7).is_none()
115    }
116
117    /// 获取股票数据; 股票代码是7位数字, 1开头说明是上海票, 2开头说明是深圳票; 其它6位数与常规股票代码一样;
118    #[inline(always)]
119    pub fn get(&self, i7: i32) -> Option<&T> {
120        self._get(i7).as_ref().map(|x| x.as_ref())
121    }
122
123    #[inline(always)]
124    pub fn get_unchecked(&self, i7: i32) -> &T {
125        self._get(i7)
126            .as_ref()
127            .unwrap_or_else(|| unreachable!("股票数据为空: {i7}"))
128    }
129
130    #[inline(always)]
131    pub fn get_mut(&self, i7: i32) -> Option<&mut T> {
132        self._get(i7).as_mut().map(|x| x.as_mut())
133    }
134
135    #[inline(always)]
136    pub fn insert(&self, i7: i32, val: T) -> Option<Box<T>> {
137        self._get(i7).replace(Box::new(val))
138    }
139
140    #[inline(always)]
141    pub fn remove(&self, i7: i32) -> Option<Box<T>> {
142        self._get(i7).take()
143    }
144}
145
146impl<T: Default> Index<i32> for StockPool<T> {
147    type Output = T;
148    fn index(&self, i7: i32) -> &Self::Output {
149        self.get(i7)
150            .unwrap_or_else(|| unreachable!("股票代码在股票池中不存在: {}", i7))
151    }
152}
153
154impl<T: Default> IndexMut<i32> for StockPool<T> {
155    fn index_mut(&mut self, i7: i32) -> &mut Self::Output {
156        self.get_mut(i7)
157            .unwrap_or_else(|| unreachable!("股票代码在股票池中不存在: {}", i7))
158    }
159}
160
161unsafe impl<T: Sync> Sync for StockPool<T> {}
162unsafe impl<T: Send> Send for StockPool<T> {}
163
164// impl iter
165// impl <T> Iterator for StockPool<T> {
166//     type Item = T;
167//     fn next(&mut self) -> Option<Self::Item> {
168//         todo!()
169//     }
170// }
171
172// impl<T: Default + Debug> IndexMut<i32> for StockPool<T> {
173//     type Output = T;
174//     fn index_mut(&mut self, index: i32) -> &mut Self::Output {
175//         self.get(i7)
176//             .expect(format!("股票代码在股票池中不存在: {}", i7).as_str())
177//     }
178// }
179
180#[test]
181fn test_stock_pool() {
182    unsafe { std::env::set_var("RUST_LOG", "debug") };
183    env_logger::init();
184
185    let pool = StockPool::<i32>::new_empty();
186    pool.insert(1000001, 100);
187    println!("pool.all_items().len {}", pool.all_items().len());
188    assert_eq!(pool[1000001], 100);
189
190    let pool = StockPool::<i32>::new_default();
191    assert_eq!(pool[1000001], 0);
192
193    let pool = StockPool::<String>::new_empty();
194    assert_eq!(pool.get(1000001), None);
195    // assert_eq!(pool[1000001], ""); // panic, because the stock code is not exist. please use fn insert to insert data.
196
197    let pool = StockPool::<String>::new_default();
198    assert_eq!(pool[1000001], "".to_string());
199
200    let pool = StockPool::<i32>::new_default();
201    println!("pool.all_items().len {}", pool.all_items().len());
202
203    let pool = StockPool::<String>::new_default();
204    assert_eq!(pool[1000001], "".to_string());
205}
206
207#[test]
208fn test_stock_pool_2() {
209    unsafe { std::env::set_var("RUST_LOG", "debug") };
210    env_logger::init();
211
212    let pool = StockPool::<i32>::new_empty();
213    for i in 1..=99999 {
214        pool.insert(1_600_000 + i, i + 100000);
215    }
216    for i in 1..=99999 {
217        pool.insert(2_000_000 + i, i + 300000);
218    }
219    for i in 1..=99999 {
220        pool.insert(2_300_000 + i, i + 300000);
221    }
222    for i in 1..=99999 {
223        pool.insert(400_000 + i, i + 400000);
224    }
225
226    for i in 1..=99999 {
227        pool.insert(1_200_000 + i, i + 220000);
228    }
229
230    for i in 1..=99999 {
231        pool.insert(1_500_000 + i, i + 550000);
232    }
233
234    for i in 1..=99999 {
235        let ii = 1_600_000 + i;
236        assert_eq!((ii, pool[ii]), (ii, i + 100000));
237    }
238    for i in 1..=99999 {
239        assert_eq!(pool[2_000_000 + i], i + 300000);
240    }
241    for i in 1..=99999 {
242        let ii = 2_300_000 + i;
243        assert_eq!((ii, pool[ii]), (ii, i + 300000));
244    }
245    for i in 1..=99999 {
246        let ii = 400_000 + i;
247        assert_eq!((ii, pool[ii]), (ii, i + 400000));
248    }
249
250    for i in 1..=99999 {
251        assert_eq!(pool[1_500_000 + i], i + 550000);
252    }
253    for i in 1..=99999 {
254        assert_eq!(pool[1_200_000 + i], i + 220000);
255    }
256}