\brief Add function to bytecode. \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. \param a_pFun Pointer to function callback. */
| 377 | \param a_pFun Pointer to function callback. |
| 378 | */ |
| 379 | void ParserByteCode::AddFun(generic_callable_type a_pFun, int a_iArgc, bool isFunctionOptimizable) |
| 380 | { |
| 381 | std::size_t sz = m_vRPN.size(); |
| 382 | bool optimize = false; |
| 383 | |
| 384 | // only optimize functions with fixed number of more than a single arguments |
| 385 | if (isFunctionOptimizable && m_bEnableOptimizer && a_iArgc > 0) |
| 386 | { |
| 387 | // <ibg 2020-06-10/> Unary Plus is a no-op |
| 388 | if (a_pFun == generic_callable_type{(erased_fun_type)&MathImpl<value_type>::UnaryPlus, nullptr}) |
| 389 | return; |
| 390 | |
| 391 | optimize = true; |
| 392 | |
| 393 | for (int i = 0; i < std::abs(a_iArgc); ++i) |
| 394 | { |
| 395 | if (m_vRPN[sz - i - 1].Cmd != cmVAL) |
| 396 | { |
| 397 | optimize = false; |
| 398 | break; |
| 399 | } |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | if (optimize) |
| 404 | { |
| 405 | value_type val = 0; |
| 406 | switch (a_iArgc) |
| 407 | { |
| 408 | case 1: val = a_pFun.call_fun<1>(m_vRPN[sz - 1].Val.data2); break; |
| 409 | case 2: val = a_pFun.call_fun<2>(m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; |
| 410 | case 3: val = a_pFun.call_fun<3>(m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; |
| 411 | case 4: val = a_pFun.call_fun<4>(m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; |
| 412 | case 5: val = a_pFun.call_fun<5>(m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; |
| 413 | case 6: val = a_pFun.call_fun<6>(m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; |
| 414 | case 7: val = a_pFun.call_fun<7>(m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; |
| 415 | case 8: val = a_pFun.call_fun<8>(m_vRPN[sz - 8].Val.data2, m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; |
| 416 | case 9: val = a_pFun.call_fun<9>(m_vRPN[sz - 9].Val.data2, m_vRPN[sz - 8].Val.data2, m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; |
| 417 | case 10: val = a_pFun.call_fun<10>(m_vRPN[sz - 10].Val.data2, m_vRPN[sz - 9].Val.data2, m_vRPN[sz - 8].Val.data2, m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; |
| 418 | default: |
| 419 | // For now functions with unlimited number of arguments are not optimized |
| 420 | throw ParserError(ecINTERNAL_ERROR); |
| 421 | } |
| 422 | |
| 423 | // remove the folded values |
| 424 | m_vRPN.erase(m_vRPN.end() - a_iArgc, m_vRPN.end()); |
| 425 | |
| 426 | SToken tok; |
| 427 | tok.Cmd = cmVAL; |
| 428 | tok.Val.data = 0; |
| 429 | tok.Val.data2 = val; |
| 430 | tok.Val.ptr = nullptr; |
| 431 | m_vRPN.push_back(tok); |
| 432 | } |
| 433 | else |
| 434 | { |
| 435 | SToken tok; |
| 436 | tok.Cmd = cmFUNC; |