use std::mem::MaybeUninit;
use arrayvec::ArrayVec;
use crate::{
vlib::{
self, BufferIndex, MainRef,
buffer::BufferRef,
node::{FRAME_SIZE, FrameRef, NextNodes, Node, NodeRuntimeRef},
},
vppinfra::{likely, unlikely},
};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FeatureNextNode<NextNode> {
DefinedNode(NextNode),
NextFeature,
}
impl<NextNode> From<NextNode> for FeatureNextNode<NextNode> {
fn from(value: NextNode) -> Self {
Self::DefinedNode(value)
}
}
pub trait GenericFeatureNodeX1<N: Node> {
unsafe fn map_buffer_to_next(
&self,
vm: &MainRef,
node: &mut NodeRuntimeRef<N>,
b0: &mut BufferRef<N::FeatureData>,
) -> FeatureNextNode<N::NextNodes>;
}
#[inline(always)]
pub unsafe fn generic_feature_node_x1<GenericNode, N, FeatureData>(
vm: &MainRef,
node: &mut NodeRuntimeRef<N>,
frame: &mut FrameRef<N>,
generic_node_impl: GenericNode,
) -> u16
where
N: Node<Vector = BufferIndex, Scalar = (), Aux = (), FeatureData = FeatureData>,
GenericNode: GenericFeatureNodeX1<N>,
FeatureData: Copy,
{
unsafe {
let mut nexts: [MaybeUninit<u16>; FRAME_SIZE] = [MaybeUninit::uninit(); FRAME_SIZE];
let mut b = ArrayVec::new();
let from = frame.get_buffers::<FRAME_SIZE>(vm, &mut b);
for (i, b0) in b.iter_mut().enumerate() {
let next = generic_node_impl.map_buffer_to_next(vm, node, b0);
let next = match next {
FeatureNextNode::NextFeature => b0.vnet_feature_next().0 as u16,
FeatureNextNode::DefinedNode(next) => next.into_u16(),
};
nexts.get_unchecked_mut(i).write(next);
}
let initialized_nexts = nexts.get_unchecked(..b.len()).assume_init_ref();
vm.buffer_enqueue_to_next(node, from, initialized_nexts);
frame.vector().len() as u16
}
}
pub trait GenericFeatureNodeX4<N: Node>: GenericFeatureNodeX1<N> {
fn prefetch_buffer_x4(
&self,
_vm: &MainRef,
_node: &mut NodeRuntimeRef<N>,
b: &mut [&mut BufferRef<N::FeatureData>; 4],
) {
b[0].prefetch_header_load();
b[1].prefetch_header_load();
b[2].prefetch_header_load();
b[3].prefetch_header_load();
}
unsafe fn map_buffer_to_next_x4(
&self,
vm: &MainRef,
node: &mut NodeRuntimeRef<N>,
b: &mut [&mut BufferRef<N::FeatureData>; 4],
) -> [FeatureNextNode<N::NextNodes>; 4];
unsafe fn trace_buffer(
&self,
_vm: &MainRef,
_node: &mut NodeRuntimeRef<N>,
_b0: &mut BufferRef<N::FeatureData>,
) {
}
}
#[inline(always)]
pub unsafe fn generic_feature_node_x4<GenericNode, N, FeatureData>(
vm: &MainRef,
node: &mut NodeRuntimeRef<N>,
frame: &mut FrameRef<N>,
generic_node_impl: GenericNode,
) -> u16
where
N: Node<Vector = BufferIndex, Scalar = (), Aux = (), FeatureData = FeatureData>,
GenericNode: GenericFeatureNodeX4<N>,
FeatureData: Copy,
{
unsafe {
let mut nexts: [MaybeUninit<u16>; FRAME_SIZE] = [MaybeUninit::uninit(); FRAME_SIZE];
let mut b = ArrayVec::new();
let from = frame.get_buffers::<FRAME_SIZE>(vm, &mut b);
let len = b.len();
for stride in 0..len / 4 {
let i = stride * 4;
if i + 8 <= len {
let stride_b = b.get_unchecked_mut(i + 4..i + 8);
let stride_b = stride_b.as_mut_array::<4>().unwrap_unchecked();
generic_node_impl.prefetch_buffer_x4(vm, node, stride_b);
}
let stride_b = b.get_unchecked_mut(i..i + 4);
let stride_nexts = nexts.get_unchecked_mut(i..i + 4);
let stride_b = stride_b.as_mut_array::<4>().unwrap_unchecked();
let stride_nexts = stride_nexts.as_mut_array::<4>().unwrap_unchecked();
if likely(
stride_b[0].vnet_buffer().feature_arc_index()
== stride_b[1].vnet_buffer().feature_arc_index()
&& stride_b[0].vnet_buffer().feature_arc_index()
== stride_b[2].vnet_buffer().feature_arc_index()
&& stride_b[0].vnet_buffer().feature_arc_index()
== stride_b[3].vnet_buffer().feature_arc_index(),
) {
let feature_next = stride_b[0].vnet_feature_next().0 as u16;
stride_nexts[0].write(feature_next);
stride_nexts[1].write(feature_next);
stride_nexts[2].write(feature_next);
stride_nexts[3].write(feature_next);
} else {
stride_nexts[0].write(stride_b[0].vnet_feature_next().0 as u16);
stride_nexts[1].write(stride_b[1].vnet_feature_next().0 as u16);
stride_nexts[2].write(stride_b[2].vnet_feature_next().0 as u16);
stride_nexts[3].write(stride_b[3].vnet_feature_next().0 as u16);
};
let feat_nexts = generic_node_impl.map_buffer_to_next_x4(vm, node, stride_b);
for (next_i, next) in feat_nexts.into_iter().enumerate() {
match next {
FeatureNextNode::NextFeature => { }
FeatureNextNode::DefinedNode(next) => {
stride_nexts[next_i].write(next.into_u16());
}
};
}
}
for i in (len / 4) * 4..len {
let b0 = b.get_unchecked_mut(i);
let mut next_val = b0.vnet_feature_next().0 as u16;
let next = generic_node_impl.map_buffer_to_next(vm, node, b0);
match next {
FeatureNextNode::NextFeature => { }
FeatureNextNode::DefinedNode(next) => next_val = next.into_u16(),
};
nexts.get_unchecked_mut(i).write(next_val);
}
if unlikely(node.flags().contains(vlib::node::NodeFlags::TRACE)) {
for b0 in &mut b {
if b0.flags().contains(vlib::BufferFlags::IS_TRACED) {
generic_node_impl.trace_buffer(vm, node, b0);
}
}
}
let initialized_nexts = nexts.get_unchecked(..b.len()).assume_init_ref();
vm.buffer_enqueue_to_next(node, from, initialized_nexts);
frame.vector().len() as u16
}
}