summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Rowe <mark@vector35.com>2025-07-31 13:28:58 -0700
committerMark Rowe <mark@vector35.com>2025-12-15 20:25:23 -0800
commit2f1150703636b2b06d84bb66853fce7382bf6f29 (patch)
tree0dbf0209a2cc9025079e664b623d3da4df1e44ab
parent8789b8690d74b7ecba68b65b061ab64befeaf539 (diff)
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`.
-rw-r--r--CMakeLists.txt6
-rw-r--r--base/CMakeLists.txt24
-rw-r--r--base/function_ref.h90
3 files changed, 120 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1c1f5263..d0aff4fc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,11 +29,17 @@ if(NOT DEMO)
endif()
endif()
+if(NOT BN_INTERNAL_BUILD)
+ add_subdirectory(base)
+endif()
+
add_library(binaryninjaapi STATIC ${BN_API_SOURCES})
target_include_directories(binaryninjaapi
PUBLIC ${PROJECT_SOURCE_DIR})
+target_link_libraries(binaryninjaapi PUBLIC binaryninjabase)
+
# Store path to user plugin dir
if(WIN32)
set(BN_USER_PLUGINS_DIR "$ENV{APPDATA}\\Binary Ninja\\plugins")
diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt
new file mode 100644
index 00000000..4c0ace90
--- /dev/null
+++ b/base/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
+
+file(GLOB BN_BASE_SOURCES CONFIGURE_DEPENDS *.cpp *.h)
+
+add_library(binaryninjabase OBJECT ${BN_BASE_SOURCES})
+set_target_properties(binaryninjabase PROPERTIES LINKER_LANGUAGE CXX)
+
+target_include_directories(binaryninjabase
+ PUBLIC ${PROJECT_SOURCE_DIR})
+
+set_target_properties(binaryninjabase PROPERTIES
+ CXX_STANDARD 20
+ CXX_VISIBILITY_PRESET hidden
+ CXX_STANDARD_REQUIRED ON
+ VISIBILITY_INLINES_HIDDEN ON
+ POSITION_INDEPENDENT_CODE ON)
+
+if(BN_REF_COUNT_DEBUG)
+ target_compile_definitions(binaryninjabase PUBLIC BN_REF_COUNT_DEBUG)
+endif()
+
+if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
+ target_compile_definitions(binaryninjabase PRIVATE BN_ENABLE_LOG_TRACE)
+endif()
diff --git a/base/function_ref.h b/base/function_ref.h
new file mode 100644
index 00000000..015cd8f2
--- /dev/null
+++ b/base/function_ref.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2025 Vector 35 Inc
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#pragma once
+
+#include <type_traits>
+#include <utility>
+#include <functional>
+
+namespace bn::base {
+
+template <typename Sig>
+class function_ref;
+
+// A non-owning reference to a callable object, inspired by C++26's std::function_ref.
+// If the callable needs to be stored or copied, use std::function instead.
+template <typename R, typename... Args>
+class function_ref<R(Args...)>
+{
+private:
+ union Storage
+ {
+ const void* object = nullptr;
+ R (*func)(Args...);
+ };
+
+ Storage m_storage;
+ R (*m_invoker)(const Storage&, Args...) = nullptr;
+
+ static R invoke_function(const Storage& storage, Args... args)
+ {
+ auto fn = storage.func;
+ return fn(std::forward<Args>(args)...);
+ }
+
+ template <typename T>
+ static R invoke_callable(const Storage& storage, Args... args)
+ {
+ return std::invoke(*static_cast<const T*>(storage.object), std::forward<Args>(args)...);
+ }
+
+public:
+ function_ref() = delete;
+
+ // Constructor that accepts a function pointer
+ function_ref(R (*f)(Args...)) noexcept
+ : m_storage{.func = f}
+ , m_invoker(&invoke_function)
+ {
+ }
+
+ // Constructor that accepts any callable object that is not function_ref
+ template<typename F>
+ requires (!std::is_same_v<std::remove_cvref_t<F>, function_ref>) &&
+ std::is_invocable_r_v<R, F&, Args...>
+ function_ref(const F& f) noexcept
+ : m_storage{.object = &f}
+ , m_invoker(&invoke_callable<std::remove_cvref_t<F>>)
+ {
+ }
+
+ R operator()(Args... args) const
+ {
+ return m_invoker(m_storage, std::forward<Args>(args)...);
+ }
+
+ function_ref(const function_ref&) noexcept = default;
+ function_ref(function_ref&&) noexcept = default;
+ function_ref& operator=(const function_ref&) noexcept = default;
+ function_ref& operator=(function_ref&&) noexcept = default;
+};
+
+} // namespace bn::base