Skip to content

Commit c73f201

Browse files
committed
rtl::constructor- wip.
1 parent 6a46e30 commit c73f201

File tree

6 files changed

+133
-3
lines changed

6 files changed

+133
-3
lines changed

ReflectionTemplateLib/rtl/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ set(LOCAL_HEADERS
1111
"${CMAKE_CURRENT_SOURCE_DIR}/rtl_constants.h"
1212
"${CMAKE_CURRENT_SOURCE_DIR}/rtl_forward_decls.h"
1313

14+
"${CMAKE_CURRENT_SOURCE_DIR}/rtl_constructor.h"
15+
1416
"${CMAKE_CURRENT_SOURCE_DIR}/rtl_function.h"
1517
"${CMAKE_CURRENT_SOURCE_DIR}/rtl_function_erased_return.h"
1618
"${CMAKE_CURRENT_SOURCE_DIR}/rtl_function_erased_return.hpp"

ReflectionTemplateLib/rtl/dispatch/function_lambda.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ namespace rtl::dispatch
1818
template<class...args_t>
1919
struct function_lambda<fn_void::no, erase::t_ctor, args_t...> : lambda
2020
{
21-
// ditch all std::functions and use fn-pointer directly - what??? Yes!
2221
using fptr_t = Return(*)(alloc, traits::normal_sign_t<args_t>&&...);
2322

2423
const fptr_t& f_ptr() const {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*************************************************************************
2+
* *
3+
* Reflection Template Library (RTL) - Modern C++ Reflection Framework *
4+
* https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP *
5+
* *
6+
* Copyright (c) 2025 Neeraj Singh <reflectcxx@outlook.com> *
7+
* SPDX-License-Identifier: MIT *
8+
* *
9+
*************************************************************************/
10+
11+
12+
#pragma once
13+
14+
#include "functor.h"
15+
#include "RObject.hpp"
16+
17+
namespace rtl
18+
{
19+
template<class ...signature_t>
20+
class constructor
21+
{
22+
using lambda_t = std::function<Return(alloc, signature_t...)>;
23+
24+
error m_init_err = error::InvalidCaller;
25+
26+
std::vector<lambda_t> m_hop = {};
27+
28+
std::vector<const dispatch::functor*> m_functors = {};
29+
30+
void set_init_error(error p_err);
31+
32+
GETTER_REF(std::vector<lambda_t>, _hop, m_hop)
33+
GETTER_REF(std::vector<const dispatch::functor*>, _overloads, m_functors)
34+
35+
public:
36+
37+
enum call_by {
38+
value = 0,
39+
cref = 1, //const ref.
40+
ncref = 2 //non-const ref.
41+
};
42+
43+
GETTER(rtl::error, _init_error, m_init_err)
44+
45+
constexpr operator bool() const noexcept;
46+
47+
template<class ...args_t>
48+
requires (sizeof...(args_t) == sizeof...(signature_t))
49+
constexpr Return operator()(args_t&&...params) const noexcept;
50+
};
51+
}

ReflectionTemplateLib/rtl/rtl_forward_decls.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ namespace rtl
3030
template<class return_t, class ...signature_t>
3131
class function;
3232

33+
template<class ...signature_t>
34+
class constructor;
35+
3336
template<class return_t, class ...signature_t>
3437
struct static_method;
3538

ReflectionTemplateLib/rtl/rtl_function_erased_return.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ namespace rtl
2323

2424
using lambda_rt = std::function<std::any(const dispatch::functor&, signature_t...)>;
2525

26+
error m_init_err = error::InvalidCaller;
27+
2628
std::vector<lambda_rt> m_rhop = {};
2729

2830
std::vector<lambda_vt> m_vhop = {};
2931

3032
std::vector<const dispatch::functor*> m_functors = {};
3133

32-
error m_init_err = error::InvalidCaller;
33-
3434
void set_init_error(error p_err);
3535

3636
GETTER_REF(std::vector<lambda_rt>, _rhop, m_rhop)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# RTL Reflection Call Overhead Analysis
2+
3+
## Overview
4+
5+
This document summarizes the flat overhead cost associated with using RTL's reflective call paths across all benchmarked call types. It categorizes overhead into **non-erased** and **erased** call paths and establishes upper and lower bounds observed across the entire test suite.
6+
7+
---
8+
9+
## Non-Erased RTL Calls (Fast Path)
10+
11+
### Summary
12+
13+
Non-erased calls (`rtl::function` / `rtl::method`) exhibit near-zero overhead in all realistic workloads and only minimal overhead in microbenchmarks.
14+
15+
### Overhead Range
16+
17+
* **Best case (real workloads):** Effectively *0 ns* overhead. Measurements match direct calls within noise.
18+
* **Worst case (scale = 0):**
19+
20+
* set: ~+0.4 ns overhead
21+
* get: ~+1.1 ns overhead
22+
* Relative cost: ~1.6×–1.8× direct call cost in pure overhead tests.
23+
24+
### Practical Interpretation
25+
26+
Non-erased RTL calls are effectively *free* for practical purposes and safe even for ultra-hot loops.
27+
28+
---
29+
30+
## Erased RTL Calls (Most Expensive Path)
31+
32+
### Absolute Worst Case (All Benchmarks)
33+
34+
The highest overhead observed occurs in fully erased `get` calls on trivial functions.
35+
36+
* **Fully Erased get:** ~+15–16 ns overhead
37+
* **Relative:** ~12×–13× slower than direct
38+
* **Condition:** Function body is trivial (scale = 0)
39+
40+
This is the *maximum possible overhead* identified.
41+
42+
### Typical Hotpath Overhead (Real Workload)
43+
44+
When the function performs meaningful computation (scale ≥ 5):
45+
46+
* **set:** +3–6% overhead
47+
* **get:** +5–10% overhead
48+
* **Erased target only:** +1–3% overhead, often nearly at parity with direct
49+
50+
### Practical Interpretation
51+
52+
Erased calls introduce a measurable cost in pure overhead scenarios, but once real work exists, the relative overhead becomes small and predictable.
53+
54+
---
55+
56+
## Flat Overhead Price Card
57+
58+
### Non-Erased RTL
59+
60+
* **Realistic Overhead:** 0–1 ns
61+
* **Pathological Worst Case:** ~1.2 ns
62+
* **Use Case:** Safe for ultra-hot loops; equivalent to direct calls and often faster than `std::function`.
63+
64+
### Erased RTL
65+
66+
* **Maximum Overhead Across All Tests:** ~16 ns
67+
* **Realistic Overhead:** +3–10% per call
68+
* **Target-Only Erasure:** +1–3%
69+
* **Use Case:** Suitable for high-performance code unless the function body is trivial.
70+
71+
---
72+
73+
## One-Line Summary
74+
75+
Across all callables, RTL's overhead ranges from **effectively zero** (non-erased) to a **maximum of ~16 ns** (fully erased trivial calls), with real-world workloads sitting comfortably at **+3–10%** overhead for erased calls.

0 commit comments

Comments
 (0)