use anyhow::Result;
use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signature::Keypair};
use crate::perf::{hardware_optimizations::BranchOptimizer, simd::SIMDMemory};
pub const BYTES_PER_ACCOUNT: usize = 32;
pub const MAX_INSTRUCTIONS_WARN: usize = 64;
pub struct Prefetch;
impl Prefetch {
#[inline(always)]
pub fn instructions(instructions: &[Instruction]) {
if instructions.is_empty() {
return;
}
unsafe {
BranchOptimizer::prefetch_read_data(&instructions[0]);
}
if instructions.len() > 2 {
unsafe {
BranchOptimizer::prefetch_read_data(&instructions[instructions.len() / 2]);
}
}
if instructions.len() > 1 {
unsafe {
BranchOptimizer::prefetch_read_data(&instructions[instructions.len() - 1]);
}
}
}
#[inline(always)]
pub fn pubkey(pubkey: &Pubkey) {
unsafe {
BranchOptimizer::prefetch_read_data(pubkey);
}
}
#[inline(always)]
pub fn keypair(keypair: &Keypair) {
unsafe {
BranchOptimizer::prefetch_read_data(keypair);
}
}
}
pub struct MemoryOps;
impl MemoryOps {
#[inline(always)]
pub unsafe fn copy(dst: *mut u8, src: *const u8, len: usize) {
SIMDMemory::copy_avx2(dst, src, len);
}
#[inline(always)]
pub unsafe fn compare(a: *const u8, b: *const u8, len: usize) -> bool {
SIMDMemory::compare_avx2(a, b, len)
}
#[inline(always)]
pub unsafe fn zero(ptr: *mut u8, len: usize) {
SIMDMemory::zero_avx2(ptr, len);
}
}
pub struct InstructionProcessor;
impl InstructionProcessor {
#[inline(always)]
pub fn preprocess(instructions: &[Instruction]) -> Result<()> {
if BranchOptimizer::unlikely(instructions.is_empty()) {
return Err(anyhow::anyhow!("Instructions empty"));
}
Prefetch::instructions(instructions);
if BranchOptimizer::unlikely(instructions.len() > MAX_INSTRUCTIONS_WARN) {
tracing::warn!(target: "sol_trade_sdk", "Large instruction count: {}", instructions.len());
}
Ok(())
}
#[inline(always)]
pub fn calculate_size(instructions: &[Instruction]) -> usize {
let mut total_size = 0;
for (i, instr) in instructions.iter().enumerate() {
unsafe {
if let Some(next_instr) = instructions.get(i + 1) {
BranchOptimizer::prefetch_read_data(next_instr);
}
}
total_size += instr.data.len();
total_size += instr.accounts.len() * BYTES_PER_ACCOUNT;
}
total_size
}
}
pub struct ExecutionPath;
impl ExecutionPath {
#[inline(always)]
pub fn is_buy(input_mint: &Pubkey) -> bool {
let is_buy = input_mint == &crate::constants::SOL_TOKEN_ACCOUNT
|| input_mint == &crate::constants::WSOL_TOKEN_ACCOUNT
|| input_mint == &crate::constants::USD1_TOKEN_ACCOUNT
|| input_mint == &crate::constants::USDC_TOKEN_ACCOUNT;
if BranchOptimizer::likely(is_buy) {
return true;
}
false
}
#[inline(always)]
pub fn select<T>(
condition: bool,
fast_path: impl FnOnce() -> T,
slow_path: impl FnOnce() -> T,
) -> T {
if BranchOptimizer::likely(condition) {
fast_path()
} else {
slow_path()
}
}
}