Skip to content

Commit 2f11507

Browse files
committed
Introduce bn::base::function_ref, a non-owning function wrapper inspired by C++26's std::function_ref
This is to `std::function` as `std::string_view` is to `std::string`.
1 parent 8789b86 commit 2f11507

File tree

3 files changed

+120
-0
lines changed

3 files changed

+120
-0
lines changed

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,17 @@ if(NOT DEMO)
2929
endif()
3030
endif()
3131

32+
if(NOT BN_INTERNAL_BUILD)
33+
add_subdirectory(base)
34+
endif()
35+
3236
add_library(binaryninjaapi STATIC ${BN_API_SOURCES})
3337

3438
target_include_directories(binaryninjaapi
3539
PUBLIC ${PROJECT_SOURCE_DIR})
3640

41+
target_link_libraries(binaryninjaapi PUBLIC binaryninjabase)
42+
3743
# Store path to user plugin dir
3844
if(WIN32)
3945
set(BN_USER_PLUGINS_DIR "$ENV{APPDATA}\\Binary Ninja\\plugins")

base/CMakeLists.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
2+
3+
file(GLOB BN_BASE_SOURCES CONFIGURE_DEPENDS *.cpp *.h)
4+
5+
add_library(binaryninjabase OBJECT ${BN_BASE_SOURCES})
6+
set_target_properties(binaryninjabase PROPERTIES LINKER_LANGUAGE CXX)
7+
8+
target_include_directories(binaryninjabase
9+
PUBLIC ${PROJECT_SOURCE_DIR})
10+
11+
set_target_properties(binaryninjabase PROPERTIES
12+
CXX_STANDARD 20
13+
CXX_VISIBILITY_PRESET hidden
14+
CXX_STANDARD_REQUIRED ON
15+
VISIBILITY_INLINES_HIDDEN ON
16+
POSITION_INDEPENDENT_CODE ON)
17+
18+
if(BN_REF_COUNT_DEBUG)
19+
target_compile_definitions(binaryninjabase PUBLIC BN_REF_COUNT_DEBUG)
20+
endif()
21+
22+
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
23+
target_compile_definitions(binaryninjabase PRIVATE BN_ENABLE_LOG_TRACE)
24+
endif()

base/function_ref.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright (c) 2025 Vector 35 Inc
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to
5+
// deal in the Software without restriction, including without limitation the
6+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7+
// sell copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19+
// IN THE SOFTWARE.
20+
21+
#pragma once
22+
23+
#include <type_traits>
24+
#include <utility>
25+
#include <functional>
26+
27+
namespace bn::base {
28+
29+
template <typename Sig>
30+
class function_ref;
31+
32+
// A non-owning reference to a callable object, inspired by C++26's std::function_ref.
33+
// If the callable needs to be stored or copied, use std::function instead.
34+
template <typename R, typename... Args>
35+
class function_ref<R(Args...)>
36+
{
37+
private:
38+
union Storage
39+
{
40+
const void* object = nullptr;
41+
R (*func)(Args...);
42+
};
43+
44+
Storage m_storage;
45+
R (*m_invoker)(const Storage&, Args...) = nullptr;
46+
47+
static R invoke_function(const Storage& storage, Args... args)
48+
{
49+
auto fn = storage.func;
50+
return fn(std::forward<Args>(args)...);
51+
}
52+
53+
template <typename T>
54+
static R invoke_callable(const Storage& storage, Args... args)
55+
{
56+
return std::invoke(*static_cast<const T*>(storage.object), std::forward<Args>(args)...);
57+
}
58+
59+
public:
60+
function_ref() = delete;
61+
62+
// Constructor that accepts a function pointer
63+
function_ref(R (*f)(Args...)) noexcept
64+
: m_storage{.func = f}
65+
, m_invoker(&invoke_function)
66+
{
67+
}
68+
69+
// Constructor that accepts any callable object that is not function_ref
70+
template<typename F>
71+
requires (!std::is_same_v<std::remove_cvref_t<F>, function_ref>) &&
72+
std::is_invocable_r_v<R, F&, Args...>
73+
function_ref(const F& f) noexcept
74+
: m_storage{.object = &f}
75+
, m_invoker(&invoke_callable<std::remove_cvref_t<F>>)
76+
{
77+
}
78+
79+
R operator()(Args... args) const
80+
{
81+
return m_invoker(m_storage, std::forward<Args>(args)...);
82+
}
83+
84+
function_ref(const function_ref&) noexcept = default;
85+
function_ref(function_ref&&) noexcept = default;
86+
function_ref& operator=(const function_ref&) noexcept = default;
87+
function_ref& operator=(function_ref&&) noexcept = default;
88+
};
89+
90+
} // namespace bn::base

0 commit comments

Comments
 (0)