commit e7ae061fa2c63bec456dd84aa54086f5ab4a42f4 Author: wehub-resource-sync Date: Mon Jul 13 12:36:49 2026 +0800 chore: import upstream snapshot with attribution diff --git a/Build-Docs/build_benchmark.md b/Build-Docs/build_benchmark.md new file mode 100644 index 0000000..8108edc --- /dev/null +++ b/Build-Docs/build_benchmark.md @@ -0,0 +1,91 @@ +# build_benchmark + +- + +你需要参考谷歌仓库中的 README 提到的构建,但是如果你照抄,几乎不可能构建并成功引入。 + +## 编译构建 + +```shell +git clone https://github.com/google/benchmark +cd .\benchmark\ +cmake -E make_directory "build" +cmake -E chdir "build" cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release ../ +cmake --build "build" --config Release -j +cmake --build "build" --config Debug -j +``` + +## install + +下面就是 install 了: + +```shell +cd build +cmake --install . --prefix "D:\CXX_LIB\benchmark" --config Release +cmake --install . --prefix "D:\CXX_LIB\benchmark" --config Debug +``` + +> [!TIP] +> `--prefix` 指定安装路径,可以随意修改。 +> 如果使用 Ninja 会略有改变,我们使用 MSVC 工具链,CMake 默认生成的 `sln` 解决方案是支持多配置的构建系统的,所以我们能直接 `--config`。 + +谷歌在 windows 中即使执行了我们前面的 install,也不会把 Debug 和 Release 复制过来,其实也没用。因为它不区分这两种产物的名字。 + +你们可以选择直接进入 `benchmark\build\src` 里将 Debug 和 Release 文件夹复制到你的安装目录 `benchmark\lib` 中。 + +其实复制过来也没用,CMake 查找不了,意思是如果你需要用 Debug 模式就把 Debug 中的库复制到 `benchmark\lib` 这个外层,就能正常查找了。 + +--- + +这种做法显然过度的愚蠢,我们通过修改 [`benchmarkTargets-debug.cmake`](../benchmark/lib/cmake/benchmark/benchmarkTargets-debug.cmake) 与 [`benchmarkTargets-release.cmake`](../benchmark/lib/cmake/benchmark/benchmarkTargets-release.cmake) 包文件,重新设置查找静态库的路径为: + +- [benchmark\lib\Debug](../benchmark/lib/Debug/) + +- [benchmark\lib\Release](../benchmark/lib/Release/) + +也得以智能的选择合适构建的库。 + +## 测试使用 + +引入库: + +```CMake +find_package(benchmark REQUIRED) +target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark) +``` + +测试代码: + +```cpp +#include + +static void test_string(benchmark::State& state) { + auto func = [](const std::string&str) { + std::string s{ str }; + }; + for (auto _ : state) { + // This code gets timed + func("乐呵.........................................................................."); + } +} + +BENCHMARK(test_string); + +static void test_string_view(benchmark::State& state) { + auto func = [](std::string_view str) { + std::string s{ str }; + }; + for (auto _ : state) { + // This code gets timed + func("乐呵.........................................................................."); + } +} + +BENCHMARK(test_string_view); +// Run the benchmark +BENCHMARK_MAIN(); +``` + +## 总结 + +其实构建成功后,具体怎么做,都可以随便你,只是我懒得在 CMakeLists.txt 中写 if 而已。还是想用 `find_package` 和 `target_link_libraries`。 diff --git a/Build-Docs/copy_pdb_files.ps1 b/Build-Docs/copy_pdb_files.ps1 new file mode 100644 index 0000000..4a531c3 --- /dev/null +++ b/Build-Docs/copy_pdb_files.ps1 @@ -0,0 +1,16 @@ +# 设置源目录和目标目录 +$SourceDir = "D:\project\abseil-cpp\build\absl" +$TargetDir = "D:\CXX_LIB\abseil-cpp\lib\Debug" + +# 确保目标目录存在 +if (-not (Test-Path -Path $TargetDir)) { + New-Item -ItemType Directory -Path $TargetDir -Force +} + +# 获取所有 .pdb 文件并复制到目标目录 +Get-ChildItem -Path $SourceDir -Recurse -Filter *.pdb | ForEach-Object { + $TargetPath = Join-Path -Path $TargetDir -ChildPath $_.Name + Copy-Item -Path $_.FullName -Destination $TargetPath -Force +} + +Write-Host "所有 .pdb 文件已复制到 $TargetDir" -ForegroundColor Green diff --git a/FTXUI/include/ftxui/component/animation.hpp b/FTXUI/include/ftxui/component/animation.hpp new file mode 100644 index 0000000..a04aea5 --- /dev/null +++ b/FTXUI/include/ftxui/component/animation.hpp @@ -0,0 +1,113 @@ +// Copyright 2022 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_ANIMATION_HPP +#define FTXUI_ANIMATION_HPP + +#include // for milliseconds, duration, steady_clock, time_point +#include // for function + +namespace ftxui::animation { +// Components who haven't completed their animation can call this function to +// request a new frame to be drawn later. +// +// When there is no new events and no animations to complete, no new frame is +// drawn. +void RequestAnimationFrame(); + +using Clock = std::chrono::steady_clock; +using TimePoint = std::chrono::time_point; +using Duration = std::chrono::duration; + +// Parameter of Component::OnAnimation(param). +class Params { + public: + explicit Params(Duration duration) : duration_(duration) {} + + /// The duration this animation step represents. + Duration duration() const { return duration_; } + + private: + Duration duration_; +}; + +namespace easing { +using Function = std::function; +// Linear interpolation (no easing) +float Linear(float p); + +// Quadratic easing; p^2 +float QuadraticIn(float p); +float QuadraticOut(float p); +float QuadraticInOut(float p); + +// Cubic easing; p^3 +float CubicIn(float p); +float CubicOut(float p); +float CubicInOut(float p); + +// Quartic easing; p^4 +float QuarticIn(float p); +float QuarticOut(float p); +float QuarticInOut(float p); + +// Quintic easing; p^5 +float QuinticIn(float p); +float QuinticOut(float p); +float QuinticInOut(float p); + +// Sine wave easing; sin(p * PI/2) +float SineIn(float p); +float SineOut(float p); +float SineInOut(float p); + +// Circular easing; sqrt(1 - p^2) +float CircularIn(float p); +float CircularOut(float p); +float CircularInOut(float p); + +// Exponential easing, base 2 +float ExponentialIn(float p); +float ExponentialOut(float p); +float ExponentialInOut(float p); + +// Exponentially-damped sine wave easing +float ElasticIn(float p); +float ElasticOut(float p); +float ElasticInOut(float p); + +// Overshooting cubic easing; +float BackIn(float p); +float BackOut(float p); +float BackInOut(float p); + +// Exponentially-decaying bounce easing +float BounceIn(float p); +float BounceOut(float p); +float BounceInOut(float p); +} // namespace easing + +class Animator { + public: + explicit Animator(float* from, + float to = 0.f, + Duration duration = std::chrono::milliseconds(250), + easing::Function easing_function = easing::Linear, + Duration delay = std::chrono::milliseconds(0)); + + void OnAnimation(Params&); + + float to() const { return to_; } + + private: + float* value_; + float from_; + float to_; + Duration duration_; + easing::Function easing_function_; + Duration current_; +}; + +} // namespace ftxui::animation + +#endif /* end of include guard: FTXUI_ANIMATION_HPP */ diff --git a/FTXUI/include/ftxui/component/captured_mouse.hpp b/FTXUI/include/ftxui/component/captured_mouse.hpp new file mode 100644 index 0000000..234e12f --- /dev/null +++ b/FTXUI/include/ftxui/component/captured_mouse.hpp @@ -0,0 +1,22 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_CAPTURED_MOUSE_HPP +#define FTXUI_CAPTURED_MOUSE_HPP + +#include + +namespace ftxui { +class CapturedMouseInterface { + public: + CapturedMouseInterface() = default; + CapturedMouseInterface(const CapturedMouseInterface&) = default; + CapturedMouseInterface(CapturedMouseInterface&&) = delete; + CapturedMouseInterface& operator=(const CapturedMouseInterface&) = default; + CapturedMouseInterface& operator=(CapturedMouseInterface&&) = delete; + virtual ~CapturedMouseInterface() = default; +}; +using CapturedMouse = std::unique_ptr; +} // namespace ftxui + +#endif /* end of include guard: FTXUI_CAPTURED_MOUSE_HPP */ diff --git a/FTXUI/include/ftxui/component/component.hpp b/FTXUI/include/ftxui/component/component.hpp new file mode 100644 index 0000000..f405d12 --- /dev/null +++ b/FTXUI/include/ftxui/component/component.hpp @@ -0,0 +1,142 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_HPP +#define FTXUI_COMPONENT_HPP + +#include // for function +#include // for make_shared, shared_ptr +#include // for forward + +#include "ftxui/component/component_base.hpp" // for Component, Components +#include "ftxui/component/component_options.hpp" // for ButtonOption, CheckboxOption, MenuOption +#include "ftxui/dom/elements.hpp" // for Element +#include "ftxui/util/ref.hpp" // for ConstRef, Ref, ConstStringRef, ConstStringListRef, StringRef + +namespace ftxui { +struct ButtonOption; +struct CheckboxOption; +struct Event; +struct InputOption; +struct MenuOption; +struct RadioboxOption; +struct MenuEntryOption; + +template +std::shared_ptr Make(Args&&... args) { + return std::make_shared(std::forward(args)...); +} + +// Pipe operator to decorate components. +using ComponentDecorator = std::function; +using ElementDecorator = std::function; +Component operator|(Component component, ComponentDecorator decorator); +Component operator|(Component component, ElementDecorator decorator); +Component& operator|=(Component& component, ComponentDecorator decorator); +Component& operator|=(Component& component, ElementDecorator decorator); + +namespace Container { +Component Vertical(Components children); +Component Vertical(Components children, int* selector); +Component Horizontal(Components children); +Component Horizontal(Components children, int* selector); +Component Tab(Components children, int* selector); +Component Stacked(Components children); +} // namespace Container + +Component Button(ButtonOption options); +Component Button(ConstStringRef label, + std::function on_click, + ButtonOption options = ButtonOption::Simple()); + +Component Checkbox(CheckboxOption options); +Component Checkbox(ConstStringRef label, + bool* checked, + CheckboxOption options = CheckboxOption::Simple()); + +Component Input(InputOption options = {}); +Component Input(StringRef content, InputOption options = {}); +Component Input(StringRef content, + StringRef placeholder, + InputOption options = {}); + +Component Menu(MenuOption options); +Component Menu(ConstStringListRef entries, + int* selected_, + MenuOption options = MenuOption::Vertical()); +Component MenuEntry(MenuEntryOption options); +Component MenuEntry(ConstStringRef label, MenuEntryOption options = {}); + +Component Radiobox(RadioboxOption options); +Component Radiobox(ConstStringListRef entries, + int* selected_, + RadioboxOption options = {}); + +Component Dropdown(ConstStringListRef entries, int* selected); +Component Dropdown(DropdownOption options); + +Component Toggle(ConstStringListRef entries, int* selected); + +// General slider constructor: +template +Component Slider(SliderOption options); + +// Shorthand without the `SliderOption` constructor: +Component Slider(ConstStringRef label, + Ref value, + ConstRef min = 0, + ConstRef max = 100, + ConstRef increment = 5); +Component Slider(ConstStringRef label, + Ref value, + ConstRef min = 0.f, + ConstRef max = 100.f, + ConstRef increment = 5.f); +Component Slider(ConstStringRef label, + Ref value, + ConstRef min = 0L, + ConstRef max = 100L, + ConstRef increment = 5L); + +Component ResizableSplit(ResizableSplitOption options); +Component ResizableSplitLeft(Component main, Component back, int* main_size); +Component ResizableSplitRight(Component main, Component back, int* main_size); +Component ResizableSplitTop(Component main, Component back, int* main_size); +Component ResizableSplitBottom(Component main, Component back, int* main_size); + +Component Renderer(Component child, std::function); +Component Renderer(std::function); +Component Renderer(std::function); +ComponentDecorator Renderer(ElementDecorator); + +Component CatchEvent(Component child, std::function); +ComponentDecorator CatchEvent(std::function on_event); + +Component Maybe(Component, const bool* show); +Component Maybe(Component, std::function); +ComponentDecorator Maybe(const bool* show); +ComponentDecorator Maybe(std::function); + +Component Modal(Component main, Component modal, const bool* show_modal); +ComponentDecorator Modal(Component modal, const bool* show_modal); + +Component Collapsible(ConstStringRef label, + Component child, + Ref show = false); + +Component Hoverable(Component component, bool* hover); +Component Hoverable(Component component, + std::function on_enter, + std::function on_leave); +Component Hoverable(Component component, // + std::function on_change); +ComponentDecorator Hoverable(bool* hover); +ComponentDecorator Hoverable(std::function on_enter, + std::function on_leave); +ComponentDecorator Hoverable(std::function on_change); + +Component Window(WindowOptions option); + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_HPP */ diff --git a/FTXUI/include/ftxui/component/component_base.hpp b/FTXUI/include/ftxui/component/component_base.hpp new file mode 100644 index 0000000..ef1b751 --- /dev/null +++ b/FTXUI/include/ftxui/component/component_base.hpp @@ -0,0 +1,101 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_BASE_HPP +#define FTXUI_COMPONENT_BASE_HPP + +#include // for unique_ptr +#include // for vector + +#include "ftxui/component/captured_mouse.hpp" // for CaptureMouse +#include "ftxui/dom/elements.hpp" // for Element + +namespace ftxui { + +class Delegate; +class Focus; +struct Event; + +namespace animation { +class Params; +} // namespace animation + +class ComponentBase; +using Component = std::shared_ptr; +using Components = std::vector; + +/// @brief It implement rendering itself as ftxui::Element. It implement +/// keyboard navigation by responding to ftxui::Event. +/// @ingroup component +class ComponentBase { + public: + explicit ComponentBase(Components children) + : children_(std::move(children)) {} + virtual ~ComponentBase(); + ComponentBase() = default; + + // A component is not copyable/movable. + ComponentBase(const ComponentBase&) = delete; + ComponentBase(ComponentBase&&) = delete; + ComponentBase& operator=(const ComponentBase&) = delete; + ComponentBase& operator=(ComponentBase&&) = delete; + + // Component hierarchy: + ComponentBase* Parent() const; + Component& ChildAt(size_t i); + size_t ChildCount() const; + int Index() const; + void Add(Component children); + void Detach(); + void DetachAllChildren(); + + // Renders the component. + virtual Element Render(); + + // Handles an event. + // By default, reduce on children with a lazy OR. + // + // Returns whether the event was handled or not. + virtual bool OnEvent(Event); + + // Handle an animation step. + virtual void OnAnimation(animation::Params& params); + + // Focus management ---------------------------------------------------------- + // + // If this component contains children, this indicates which one is active, + // nullptr if none is active. + // + // We say an element has the focus if the chain of ActiveChild() from the + // root component contains this object. + virtual Component ActiveChild(); + + // Return true when the component contains focusable elements. + // The non focusable Component will be skipped when navigating using the + // keyboard. + virtual bool Focusable() const; + + // Whether this is the active child of its parent. + bool Active() const; + // Whether all the ancestors are active. + bool Focused() const; + + // Make the |child| to be the "active" one. + virtual void SetActiveChild(ComponentBase* child); + void SetActiveChild(Component child); + + // Configure all the ancestors to give focus to this component. + void TakeFocus(); + + protected: + CapturedMouse CaptureMouse(const Event& event); + + Components children_; + + private: + ComponentBase* parent_ = nullptr; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_BASE_HPP */ diff --git a/FTXUI/include/ftxui/component/component_options.hpp b/FTXUI/include/ftxui/component/component_options.hpp new file mode 100644 index 0000000..e9dd084 --- /dev/null +++ b/FTXUI/include/ftxui/component/component_options.hpp @@ -0,0 +1,284 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP +#define FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP + +#include // for milliseconds +#include // for Duration, QuadraticInOut, Function +#include // for Direction, Direction::Left, Direction::Right, Direction::Down +#include // for Element, separator +#include // for Ref, ConstRef, StringRef +#include // for function +#include // for string + +#include "ftxui/component/component_base.hpp" // for Component +#include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White + +namespace ftxui { + +/// @brief arguments for |ButtonOption::transform|, |CheckboxOption::transform|, +/// |Radiobox::transform|, |MenuEntryOption::transform|, +/// |MenuOption::transform|. +struct EntryState { + std::string label; ///< The label to display. + bool state; ///< The state of the button/checkbox/radiobox + bool active; ///< Whether the entry is the active one. + bool focused; ///< Whether the entry is one focused by the user. + int index; ///< Index of the entry when applicable or -1. +}; + +struct UnderlineOption { + bool enabled = false; + + Color color_active = Color::White; + Color color_inactive = Color::GrayDark; + + animation::easing::Function leader_function = + animation::easing::QuadraticInOut; + animation::easing::Function follower_function = + animation::easing::QuadraticInOut; + + animation::Duration leader_duration = std::chrono::milliseconds(250); + animation::Duration leader_delay = std::chrono::milliseconds(0); + animation::Duration follower_duration = std::chrono::milliseconds(250); + animation::Duration follower_delay = std::chrono::milliseconds(0); + + void SetAnimation(animation::Duration d, animation::easing::Function f); + void SetAnimationDuration(animation::Duration d); + void SetAnimationFunction(animation::easing::Function f); + void SetAnimationFunction(animation::easing::Function f_leader, + animation::easing::Function f_follower); +}; + +/// @brief Option about a potentially animated color. +/// @ingroup component +struct AnimatedColorOption { + void Set( + Color inactive, + Color active, + animation::Duration duration = std::chrono::milliseconds(250), + animation::easing::Function function = animation::easing::QuadraticInOut); + + bool enabled = false; + Color inactive; + Color active; + animation::Duration duration = std::chrono::milliseconds(250); + animation::easing::Function function = animation::easing::QuadraticInOut; +}; + +struct AnimatedColorsOption { + AnimatedColorOption background; + AnimatedColorOption foreground; +}; + +/// @brief Option for the MenuEntry component. +/// @ingroup component +struct MenuEntryOption { + ConstStringRef label = "MenuEntry"; + std::function transform; + AnimatedColorsOption animated_colors; +}; + +/// @brief Option for the Menu component. +/// @ingroup component +struct MenuOption { + // Standard constructors: + static MenuOption Horizontal(); + static MenuOption HorizontalAnimated(); + static MenuOption Vertical(); + static MenuOption VerticalAnimated(); + static MenuOption Toggle(); + + ConstStringListRef entries; ///> The list of entries. + Ref selected = 0; ///> The index of the selected entry. + + // Style: + UnderlineOption underline; + MenuEntryOption entries_option; + Direction direction = Direction::Down; + std::function elements_prefix; + std::function elements_infix; + std::function elements_postfix; + + // Observers: + std::function on_change; ///> Called when the selected entry changes. + std::function on_enter; ///> Called when the user presses enter. + Ref focused_entry = 0; +}; + +/// @brief Option for the AnimatedButton component. +/// @ingroup component +struct ButtonOption { + // Standard constructors: + static ButtonOption Ascii(); + static ButtonOption Simple(); + static ButtonOption Border(); + static ButtonOption Animated(); + static ButtonOption Animated(Color color); + static ButtonOption Animated(Color background, Color foreground); + static ButtonOption Animated(Color background, + Color foreground, + Color background_active, + Color foreground_active); + + ConstStringRef label = "Button"; + std::function on_click = [] {}; + + // Style: + std::function transform; + AnimatedColorsOption animated_colors; +}; + +/// @brief Option for the Checkbox component. +/// @ingroup component +struct CheckboxOption { + // Standard constructors: + static CheckboxOption Simple(); + + ConstStringRef label = "Checkbox"; + + Ref checked = false; + + // Style: + std::function transform; + + // Observer: + /// Called when the user change the state. + std::function on_change = [] {}; +}; + +/// @brief Used to define style for the Input component. +struct InputState { + Element element; + bool hovered; ///< Whether the input is hovered by the mouse. + bool focused; ///< Whether the input is focused by the user. + bool is_placeholder; ///< Whether the input is empty and displaying the + ///< placeholder. +}; + +/// @brief Option for the Input component. +/// @ingroup component +struct InputOption { + // A set of predefined styles: + + /// @brief Create the default input style: + static InputOption Default(); + /// @brief A white on black style with high margins: + static InputOption Spacious(); + + /// The content of the input. + StringRef content = ""; + + /// The content of the input when it's empty. + StringRef placeholder = ""; + + // Style: + std::function transform; + Ref password = false; ///< Obscure the input content using '*'. + Ref multiline = true; ///< Whether the input can be multiline. + Ref insert = true; ///< Insert or overtype character mode. + + /// Called when the content changes. + std::function on_change = [] {}; + /// Called when the user presses enter. + std::function on_enter = [] {}; + + // The char position of the cursor: + Ref cursor_position = 0; +}; + +/// @brief Option for the Radiobox component. +/// @ingroup component +struct RadioboxOption { + // Standard constructors: + static RadioboxOption Simple(); + + // Content: + ConstStringListRef entries; + Ref selected = 0; + + // Style: + std::function transform; + + // Observers: + /// Called when the selected entry changes. + std::function on_change = [] {}; + Ref focused_entry = 0; +}; + +struct ResizableSplitOption { + Component main; + Component back; + Ref direction = Direction::Left; + Ref main_size = + (direction() == Direction::Left || direction() == Direction::Right) ? 20 + : 10; + std::function separator_func = [] { return ::ftxui::separator(); }; +}; + +// @brief Option for the `Slider` component. +// @ingroup component +template +struct SliderOption { + Ref value; + ConstRef min = T(0); + ConstRef max = T(100); + ConstRef increment = (max() - min()) / 20; + Direction direction = Direction::Right; + Color color_active = Color::White; + Color color_inactive = Color::GrayDark; + std::function on_change; ///> Called when `value` is updated. +}; + +// Parameter pack used by `WindowOptions::render`. +struct WindowRenderState { + Element inner; ///< The element wrapped inside this window. + const std::string& title; ///< The title of the window. + bool active = false; ///< Whether the window is the active one. + bool drag = false; ///< Whether the window is being dragged. + bool resize = false; ///< Whether the window is being resized. + bool hover_left = false; ///< Whether the resizeable left side is hovered. + bool hover_right = false; ///< Whether the resizeable right side is hovered. + bool hover_top = false; ///< Whether the resizeable top side is hovered. + bool hover_down = false; ///< Whether the resizeable down side is hovered. +}; + +// @brief Option for the `Window` component. +// @ingroup component +struct WindowOptions { + Component inner; ///< The component wrapped by this window. + ConstStringRef title = ""; ///< The title displayed by this window. + + Ref left = 0; ///< The left side position of the window. + Ref top = 0; ///< The top side position of the window. + Ref width = 20; ///< The width of the window. + Ref height = 10; ///< The height of the window. + + Ref resize_left = true; ///< Can the left side be resized? + Ref resize_right = true; ///< Can the right side be resized? + Ref resize_top = true; ///< Can the top side be resized? + Ref resize_down = true; ///< Can the down side be resized? + + /// An optional function to customize how the window looks like: + std::function render; +}; + +/// @brief Option for the Dropdown component. +/// @ingroup component +/// A dropdown menu is a checkbox opening/closing a radiobox. +struct DropdownOption { + /// Whether the dropdown is open or closed: + Ref open = false; + // The options for the checkbox: + CheckboxOption checkbox; + // The options for the radiobox: + RadioboxOption radiobox; + // The transformation function: + std::function + transform; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP */ diff --git a/FTXUI/include/ftxui/component/event.hpp b/FTXUI/include/ftxui/component/event.hpp new file mode 100644 index 0000000..6ce20e0 --- /dev/null +++ b/FTXUI/include/ftxui/component/event.hpp @@ -0,0 +1,152 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_EVENT_HPP +#define FTXUI_COMPONENT_EVENT_HPP + +#include // for Mouse +#include // for string, operator== + +namespace ftxui { + +class ScreenInteractive; +class ComponentBase; + +/// @brief Represent an event. It can be key press event, a terminal resize, or +/// more ... +/// +/// For example: +/// - Printable character can be created using Event::Character('a'). +/// - Some special are predefined, like Event::ArrowLeft. +/// - One can find arbitrary code for special Events using: +/// ./example/util/print_key_press +/// For instance, CTLR+A maps to Event::Special({1}); +/// +/// Useful documentation about xterm specification: +/// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html +struct Event { + // --- Constructor section --------------------------------------------------- + static Event Character(std::string); + static Event Character(char); + static Event Character(wchar_t); + static Event Special(std::string); + static Event Mouse(std::string, Mouse mouse); + static Event CursorPosition(std::string, int x, int y); // Internal + static Event CursorShape(std::string, int shape); // Internal + + // --- Arrow --- + static const Event ArrowLeft; + static const Event ArrowRight; + static const Event ArrowUp; + static const Event ArrowDown; + + static const Event ArrowLeftCtrl; + static const Event ArrowRightCtrl; + static const Event ArrowUpCtrl; + static const Event ArrowDownCtrl; + + // --- Other --- + static const Event Backspace; + static const Event Delete; + static const Event Return; + static const Event Escape; + static const Event Tab; + static const Event TabReverse; + + // --- Navigation keys --- + static const Event Insert; + static const Event Home; + static const Event End; + static const Event PageUp; + static const Event PageDown; + + // --- Function keys --- + static const Event F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12; + + // --- Control keys --- + static const Event a, A, CtrlA, AltA, CtrlAltA; + static const Event b, B, CtrlB, AltB, CtrlAltB; + static const Event c, C, CtrlC, AltC, CtrlAltC; + static const Event d, D, CtrlD, AltD, CtrlAltD; + static const Event e, E, CtrlE, AltE, CtrlAltE; + static const Event f, F, CtrlF, AltF, CtrlAltF; + static const Event g, G, CtrlG, AltG, CtrlAltG; + static const Event h, H, CtrlH, AltH, CtrlAltH; + static const Event i, I, CtrlI, AltI, CtrlAltI; + static const Event j, J, CtrlJ, AltJ, CtrlAltJ; + static const Event k, K, CtrlK, AltK, CtrlAltK; + static const Event l, L, CtrlL, AltL, CtrlAltL; + static const Event m, M, CtrlM, AltM, CtrlAltM; + static const Event n, N, CtrlN, AltN, CtrlAltN; + static const Event o, O, CtrlO, AltO, CtrlAltO; + static const Event p, P, CtrlP, AltP, CtrlAltP; + static const Event q, Q, CtrlQ, AltQ, CtrlAltQ; + static const Event r, R, CtrlR, AltR, CtrlAltR; + static const Event s, S, CtrlS, AltS, CtrlAltS; + static const Event t, T, CtrlT, AltT, CtrlAltT; + static const Event u, U, CtrlU, AltU, CtrlAltU; + static const Event v, V, CtrlV, AltV, CtrlAltV; + static const Event w, W, CtrlW, AltW, CtrlAltW; + static const Event x, X, CtrlX, AltX, CtrlAltX; + static const Event y, Y, CtrlY, AltY, CtrlAltY; + static const Event z, Z, CtrlZ, AltZ, CtrlAltZ; + + // --- Custom --- + static const Event Custom; + + //--- Method section --------------------------------------------------------- + bool operator==(const Event& other) const { return input_ == other.input_; } + bool operator!=(const Event& other) const { return !operator==(other); } + bool operator<(const Event& other) const { return input_ < other.input_; } + + const std::string& input() const { return input_; } + + bool is_character() const { return type_ == Type::Character; } + std::string character() const { return input_; } + + bool is_mouse() const { return type_ == Type::Mouse; } + struct Mouse& mouse() { return data_.mouse; } + + // --- Internal Method section ----------------------------------------------- + bool is_cursor_position() const { return type_ == Type::CursorPosition; } + int cursor_x() const { return data_.cursor.x; } + int cursor_y() const { return data_.cursor.y; } + + bool is_cursor_shape() const { return type_ == Type::CursorShape; } + int cursor_shape() const { return data_.cursor_shape; } + + // Debug + std::string DebugString() const; + + //--- State section ---------------------------------------------------------- + ScreenInteractive* screen_ = nullptr; + + private: + friend ComponentBase; + friend ScreenInteractive; + enum class Type { + Unknown, + Character, + Mouse, + CursorPosition, + CursorShape, + }; + Type type_ = Type::Unknown; + + struct Cursor { + int x = 0; + int y = 0; + }; + + union { + struct Mouse mouse; + struct Cursor cursor; + int cursor_shape; + } data_ = {}; + + std::string input_; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_EVENT_HPP */ diff --git a/FTXUI/include/ftxui/component/loop.hpp b/FTXUI/include/ftxui/component/loop.hpp new file mode 100644 index 0000000..faef475 --- /dev/null +++ b/FTXUI/include/ftxui/component/loop.hpp @@ -0,0 +1,41 @@ +// Copyright 2022 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_LOOP_HPP +#define FTXUI_COMPONENT_LOOP_HPP + +#include // for shared_ptr + +#include "ftxui/component/component_base.hpp" // for ComponentBase + +namespace ftxui { +class ComponentBase; + +using Component = std::shared_ptr; +class ScreenInteractive; + +class Loop { + public: + Loop(ScreenInteractive* screen, Component component); + ~Loop(); + + bool HasQuitted(); + void RunOnce(); + void RunOnceBlocking(); + void Run(); + + // This class is non copyable/movable. + Loop(const Loop&) = default; + Loop(Loop&&) = delete; + Loop& operator=(Loop&&) = delete; + Loop(const ScreenInteractive&) = delete; + Loop& operator=(const Loop&) = delete; + + private: + ScreenInteractive* screen_; + Component component_; +}; + +} // namespace ftxui + +#endif // FTXUI_COMPONENT_LOOP_HPP diff --git a/FTXUI/include/ftxui/component/mouse.hpp b/FTXUI/include/ftxui/component/mouse.hpp new file mode 100644 index 0000000..cc6c3f1 --- /dev/null +++ b/FTXUI/include/ftxui/component/mouse.hpp @@ -0,0 +1,47 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_MOUSE_HPP +#define FTXUI_COMPONENT_MOUSE_HPP +namespace ftxui { + +/// @brief A mouse event. It contains the coordinate of the mouse, the button +/// pressed and the modifier (shift, ctrl, meta). +/// @ingroup component +struct Mouse { + enum Button { + Left = 0, + Middle = 1, + Right = 2, + None = 3, + WheelUp = 4, + WheelDown = 5, + WheelLeft = 6, /// Supported terminal only. + WheelRight = 7, /// Supported terminal only. + }; + + enum Motion { + Released = 0, + Pressed = 1, + Moved = 2, + }; + + // Button + Button button = Button::None; + + // Motion + Motion motion = Motion::Pressed; + + // Modifiers: + bool shift = false; + bool meta = false; + bool control = false; + + // Coordinates: + int x = 0; + int y = 0; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_MOUSE_HPP */ diff --git a/FTXUI/include/ftxui/component/receiver.hpp b/FTXUI/include/ftxui/component/receiver.hpp new file mode 100644 index 0000000..55189cf --- /dev/null +++ b/FTXUI/include/ftxui/component/receiver.hpp @@ -0,0 +1,145 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_RECEIVER_HPP_ +#define FTXUI_COMPONENT_RECEIVER_HPP_ + +#include // for copy, max +#include // for atomic, __atomic_base +#include // for condition_variable +#include // for unique_ptr, make_unique +#include // for mutex, unique_lock +#include // for queue +#include // for move + +namespace ftxui { + +// Usage: +// +// Initialization: +// --------------- +// +// auto receiver = MakeReceiver(); +// auto sender_1= receiver->MakeSender(); +// auto sender_2 = receiver->MakeSender(); +// +// Then move the senders elsewhere, potentially in a different thread. +// +// On the producer side: +// ---------------------- +// [thread 1] sender_1->Send("hello"); +// [thread 2] sender_2->Send("world"); +// +// On the consumer side: +// --------------------- +// char c; +// while(receiver->Receive(&c)) // Return true as long as there is a producer. +// print(c) +// +// Receiver::Receive() returns true when there are no more senders. + +// clang-format off +template class SenderImpl; +template class ReceiverImpl; + +template using Sender = std::unique_ptr>; +template using Receiver = std::unique_ptr>; +template Receiver MakeReceiver(); +// clang-format on + +// ---- Implementation part ---- + +template +class SenderImpl { + public: + SenderImpl(const SenderImpl&) = delete; + SenderImpl(SenderImpl&&) = delete; + SenderImpl& operator=(const SenderImpl&) = delete; + SenderImpl& operator=(SenderImpl&&) = delete; + void Send(T t) { receiver_->Receive(std::move(t)); } + ~SenderImpl() { receiver_->ReleaseSender(); } + + Sender Clone() { return receiver_->MakeSender(); } + + private: + friend class ReceiverImpl; + explicit SenderImpl(ReceiverImpl* consumer) : receiver_(consumer) {} + ReceiverImpl* receiver_; +}; + +template +class ReceiverImpl { + public: + Sender MakeSender() { + std::unique_lock lock(mutex_); + senders_++; + return std::unique_ptr>(new SenderImpl(this)); + } + ReceiverImpl() = default; + + bool Receive(T* t) { + while (senders_ || !queue_.empty()) { + std::unique_lock lock(mutex_); + if (queue_.empty()) { + notifier_.wait(lock); + } + if (queue_.empty()) { + continue; + } + *t = std::move(queue_.front()); + queue_.pop(); + return true; + } + return false; + } + + bool ReceiveNonBlocking(T* t) { + std::unique_lock lock(mutex_); + if (queue_.empty()) { + return false; + } + *t = queue_.front(); + queue_.pop(); + return true; + } + + bool HasPending() { + std::unique_lock lock(mutex_); + return !queue_.empty(); + } + + bool HasQuitted() { + std::unique_lock lock(mutex_); + return queue_.empty() && !senders_; + } + + private: + friend class SenderImpl; + + void Receive(T t) { + { + std::unique_lock lock(mutex_); + queue_.push(std::move(t)); + } + notifier_.notify_one(); + } + + void ReleaseSender() { + senders_--; + notifier_.notify_one(); + } + + std::mutex mutex_; + std::queue queue_; + std::condition_variable notifier_; + std::atomic senders_{0}; +}; + +template +Receiver MakeReceiver() { + return std::make_unique>(); +} + +} // namespace ftxui + +#endif // FTXUI_COMPONENT_RECEIVER_HPP_ diff --git a/FTXUI/include/ftxui/component/screen_interactive.hpp b/FTXUI/include/ftxui/component/screen_interactive.hpp new file mode 100644 index 0000000..a2909fc --- /dev/null +++ b/FTXUI/include/ftxui/component/screen_interactive.hpp @@ -0,0 +1,167 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP +#define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP + +#include // for atomic +#include // for Receiver, Sender +#include // for function +#include // for shared_ptr +#include // for string +#include // for thread +#include // for variant + +#include "ftxui/component/animation.hpp" // for TimePoint +#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse +#include "ftxui/component/event.hpp" // for Event +#include "ftxui/component/task.hpp" // for Task, Closure +#include "ftxui/dom/selection.hpp" // for SelectionOption +#include "ftxui/screen/screen.hpp" // for Screen + +namespace ftxui { +class ComponentBase; +class Loop; +struct Event; + +using Component = std::shared_ptr; +class ScreenInteractivePrivate; + +class ScreenInteractive : public Screen { + public: + // Constructors: + static ScreenInteractive FixedSize(int dimx, int dimy); + static ScreenInteractive Fullscreen(); + static ScreenInteractive FullscreenPrimaryScreen(); + static ScreenInteractive FullscreenAlternateScreen(); + static ScreenInteractive FitComponent(); + static ScreenInteractive TerminalOutput(); + + // Options. Must be called before Loop(). + void TrackMouse(bool enable = true); + + // Return the currently active screen, nullptr if none. + static ScreenInteractive* Active(); + + // Start/Stop the main loop. + void Loop(Component); + void Exit(); + Closure ExitLoopClosure(); + + // Post tasks to be executed by the loop. + void Post(Task task); + void PostEvent(Event event); + void RequestAnimationFrame(); + + CapturedMouse CaptureMouse(); + + // Decorate a function. The outputted one will execute similarly to the + // inputted one, but with the currently active screen terminal hooks + // temporarily uninstalled. + Closure WithRestoredIO(Closure); + + // FTXUI implements handlers for Ctrl-C and Ctrl-Z. By default, these handlers + // are executed, even if the component catches the event. This avoid users + // handling every event to be trapped in the application. However, in some + // cases, the application may want to handle these events itself. In this + // case, the application can force FTXUI to not handle these events by calling + // the following functions with force=true. + void ForceHandleCtrlC(bool force); + void ForceHandleCtrlZ(bool force); + + // Selection API. + std::string GetSelection(); + void SelectionChange(std::function callback); + + private: + void ExitNow(); + + void Install(); + void Uninstall(); + + void PreMain(); + void PostMain(); + + bool HasQuitted(); + void RunOnce(Component component); + void RunOnceBlocking(Component component); + + void HandleTask(Component component, Task& task); + bool HandleSelection(bool handled, Event event); + void RefreshSelection(); + void Draw(Component component); + void ResetCursorPosition(); + + void Signal(int signal); + + ScreenInteractive* suspended_screen_ = nullptr; + enum class Dimension { + FitComponent, + Fixed, + Fullscreen, + TerminalOutput, + }; + Dimension dimension_ = Dimension::Fixed; + bool use_alternative_screen_ = false; + ScreenInteractive(int dimx, + int dimy, + Dimension dimension, + bool use_alternative_screen); + + bool track_mouse_ = true; + + Sender task_sender_; + Receiver task_receiver_; + + std::string set_cursor_position; + std::string reset_cursor_position; + + std::atomic quit_{false}; + std::thread event_listener_; + std::thread animation_listener_; + bool animation_requested_ = false; + animation::TimePoint previous_animation_time_; + + int cursor_x_ = 1; + int cursor_y_ = 1; + + bool mouse_captured = false; + bool previous_frame_resized_ = false; + + bool frame_valid_ = false; + + bool force_handle_ctrl_c_ = true; + bool force_handle_ctrl_z_ = true; + + // The style of the cursor to restore on exit. + int cursor_reset_shape_ = 1; + + // Selection API: + CapturedMouse selection_pending_; + struct SelectionData { + int start_x = -1; + int start_y = -1; + int end_x = -2; + int end_y = -2; + bool empty = true; + bool operator==(const SelectionData& other) const; + bool operator!=(const SelectionData& other) const; + }; + SelectionData selection_data_; + SelectionData selection_data_previous_; + std::unique_ptr selection_; + std::function selection_on_change_; + + friend class Loop; + + public: + class Private { + public: + static void Signal(ScreenInteractive& s, int signal) { s.Signal(signal); } + }; + friend Private; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP */ diff --git a/FTXUI/include/ftxui/component/task.hpp b/FTXUI/include/ftxui/component/task.hpp new file mode 100644 index 0000000..6a770e8 --- /dev/null +++ b/FTXUI/include/ftxui/component/task.hpp @@ -0,0 +1,17 @@ +// Copyright 2022 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_ANIMATION_HPP +#define FTXUI_COMPONENT_ANIMATION_HPP + +#include +#include +#include "ftxui/component/event.hpp" + +namespace ftxui { +class AnimationTask {}; +using Closure = std::function; +using Task = std::variant; +} // namespace ftxui + +#endif // FTXUI_COMPONENT_ANIMATION_HPP diff --git a/FTXUI/include/ftxui/dom/canvas.hpp b/FTXUI/include/ftxui/dom/canvas.hpp new file mode 100644 index 0000000..5d33d67 --- /dev/null +++ b/FTXUI/include/ftxui/dom/canvas.hpp @@ -0,0 +1,147 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_CANVAS_HPP +#define FTXUI_DOM_CANVAS_HPP + +#include // for size_t +#include // for function +#include // for string +#include // for unordered_map + +#include "ftxui/screen/color.hpp" // for Color +#include "ftxui/screen/image.hpp" // for Pixel, Image + +#ifdef DrawText +// Workaround for WinUsr.h (via Windows.h) defining macros that break things. +// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawtext +#undef DrawText +#endif + +namespace ftxui { + +struct Canvas { + public: + Canvas() = default; + Canvas(int width, int height); + + // Getters: + int width() const { return width_; } + int height() const { return height_; } + Pixel GetPixel(int x, int y) const; + + using Stylizer = std::function; + + // Draws using braille characters -------------------------------------------- + void DrawPointOn(int x, int y); + void DrawPointOff(int x, int y); + void DrawPointToggle(int x, int y); + void DrawPoint(int x, int y, bool value); + void DrawPoint(int x, int y, bool value, const Stylizer& s); + void DrawPoint(int x, int y, bool value, const Color& color); + void DrawPointLine(int x1, int y1, int x2, int y2); + void DrawPointLine(int x1, int y1, int x2, int y2, const Stylizer& s); + void DrawPointLine(int x1, int y1, int x2, int y2, const Color& color); + void DrawPointCircle(int x, int y, int radius); + void DrawPointCircle(int x, int y, int radius, const Stylizer& s); + void DrawPointCircle(int x, int y, int radius, const Color& color); + void DrawPointCircleFilled(int x, int y, int radius); + void DrawPointCircleFilled(int x, int y, int radius, const Stylizer& s); + void DrawPointCircleFilled(int x, int y, int radius, const Color& color); + void DrawPointEllipse(int x, int y, int r1, int r2); + void DrawPointEllipse(int x, int y, int r1, int r2, const Color& color); + void DrawPointEllipse(int x, int y, int r1, int r2, const Stylizer& s); + void DrawPointEllipseFilled(int x, int y, int r1, int r2); + void DrawPointEllipseFilled(int x, int y, int r1, int r2, const Color& color); + void DrawPointEllipseFilled(int x, int y, int r1, int r2, const Stylizer& s); + + // Draw using box characters ------------------------------------------------- + // Block are of size 1x2. y is considered to be a multiple of 2. + void DrawBlockOn(int x, int y); + void DrawBlockOff(int x, int y); + void DrawBlockToggle(int x, int y); + void DrawBlock(int x, int y, bool value); + void DrawBlock(int x, int y, bool value, const Stylizer& s); + void DrawBlock(int x, int y, bool value, const Color& color); + void DrawBlockLine(int x1, int y1, int x2, int y2); + void DrawBlockLine(int x1, int y1, int x2, int y2, const Stylizer& s); + void DrawBlockLine(int x1, int y1, int x2, int y2, const Color& color); + void DrawBlockCircle(int x1, int y1, int radius); + void DrawBlockCircle(int x1, int y1, int radius, const Stylizer& s); + void DrawBlockCircle(int x1, int y1, int radius, const Color& color); + void DrawBlockCircleFilled(int x1, int y1, int radius); + void DrawBlockCircleFilled(int x1, int y1, int radius, const Stylizer& s); + void DrawBlockCircleFilled(int x1, int y1, int radius, const Color& color); + void DrawBlockEllipse(int x1, int y1, int r1, int r2); + void DrawBlockEllipse(int x1, int y1, int r1, int r2, const Stylizer& s); + void DrawBlockEllipse(int x1, int y1, int r1, int r2, const Color& color); + void DrawBlockEllipseFilled(int x1, int y1, int r1, int r2); + void DrawBlockEllipseFilled(int x1, + int y1, + int r1, + int r2, + const Stylizer& s); + void DrawBlockEllipseFilled(int x1, + int y1, + int r1, + int r2, + const Color& color); + + // Draw using normal characters ---------------------------------------------- + // Draw using character of size 2x4 at position (x,y) + // x is considered to be a multiple of 2. + // y is considered to be a multiple of 4. + void DrawText(int x, int y, const std::string& value); + void DrawText(int x, int y, const std::string& value, const Color& color); + void DrawText(int x, int y, const std::string& value, const Stylizer& style); + + // Draw using directly pixels or images -------------------------------------- + // x is considered to be a multiple of 2. + // y is considered to be a multiple of 4. + void DrawPixel(int x, int y, const Pixel&); + void DrawImage(int x, int y, const Image&); + + // Decorator: + // x is considered to be a multiple of 2. + // y is considered to be a multiple of 4. + void Style(int x, int y, const Stylizer& style); + + private: + bool IsIn(int x, int y) const { + return x >= 0 && x < width_ && y >= 0 && y < height_; + } + + enum CellType { + kCell, // Units of size 2x4 + kBlock, // Units of size 2x2 + kBraille, // Units of size 1x1 + }; + + struct Cell { + CellType type = kCell; + Pixel content; + }; + + struct XY { + int x; + int y; + bool operator==(const XY& other) const { + return x == other.x && y == other.y; + } + }; + + struct XYHash { + size_t operator()(const XY& xy) const { + constexpr size_t shift = 1024; + return size_t(xy.x) * shift + size_t(xy.y); + } + }; + + int width_ = 0; + int height_ = 0; + std::unordered_map storage_; +}; + +} // namespace ftxui + +#endif // FTXUI_DOM_CANVAS_HPP diff --git a/FTXUI/include/ftxui/dom/deprecated.hpp b/FTXUI/include/ftxui/dom/deprecated.hpp new file mode 100644 index 0000000..78c66f1 --- /dev/null +++ b/FTXUI/include/ftxui/dom/deprecated.hpp @@ -0,0 +1,16 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_DEPRECATED_HPP +#define FTXUI_DOM_DEPRECATED_HPP + +#include +#include + +namespace ftxui { +Element text(std::wstring text); +Element vtext(std::wstring text); +Elements paragraph(std::wstring text); +} // namespace ftxui + +#endif // FTXUI_DOM_DEPRECATED_HPP diff --git a/FTXUI/include/ftxui/dom/direction.hpp b/FTXUI/include/ftxui/dom/direction.hpp new file mode 100644 index 0000000..2a38f09 --- /dev/null +++ b/FTXUI/include/ftxui/dom/direction.hpp @@ -0,0 +1,17 @@ +// Copyright 2023 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_DIRECTION_HPP +#define FTXUI_DOM_DIRECTION_HPP + +namespace ftxui { +enum class Direction { + Up = 0, + Down = 1, + Left = 2, + Right = 3, +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_DOM_DIRECTION_HPP */ diff --git a/FTXUI/include/ftxui/dom/elements.hpp b/FTXUI/include/ftxui/dom/elements.hpp new file mode 100644 index 0000000..fa16080 --- /dev/null +++ b/FTXUI/include/ftxui/dom/elements.hpp @@ -0,0 +1,201 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_ELEMENTS_HPP +#define FTXUI_DOM_ELEMENTS_HPP + +#include +#include + +#include "ftxui/dom/canvas.hpp" +#include "ftxui/dom/direction.hpp" +#include "ftxui/dom/flexbox_config.hpp" +#include "ftxui/dom/linear_gradient.hpp" +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" +#include "ftxui/screen/terminal.hpp" +#include "ftxui/util/ref.hpp" + +namespace ftxui { +class Node; +using Element = std::shared_ptr; +using Elements = std::vector; +using Decorator = std::function; +using GraphFunction = std::function(int, int)>; + +enum BorderStyle { + LIGHT, + DASHED, + HEAVY, + DOUBLE, + ROUNDED, + EMPTY, +}; + +// Pipe elements into decorator togethers. +// For instance the next lines are equivalents: +// -> text("ftxui") | bold | underlined +// -> underlined(bold(text("FTXUI"))) +Element operator|(Element, Decorator); +Element& operator|=(Element&, Decorator); +Elements operator|(Elements, Decorator); +Decorator operator|(Decorator, Decorator); + +// --- Widget --- +Element text(std::string text); +Element vtext(std::string text); +Element separator(); +Element separatorLight(); +Element separatorDashed(); +Element separatorHeavy(); +Element separatorDouble(); +Element separatorEmpty(); +Element separatorStyled(BorderStyle); +Element separator(Pixel); +Element separatorCharacter(std::string); +Element separatorHSelector(float left, + float right, + Color unselected_color, + Color selected_color); +Element separatorVSelector(float up, + float down, + Color unselected_color, + Color selected_color); +Element gauge(float progress); +Element gaugeLeft(float progress); +Element gaugeRight(float progress); +Element gaugeUp(float progress); +Element gaugeDown(float progress); +Element gaugeDirection(float progress, Direction direction); +Element border(Element); +Element borderLight(Element); +Element borderDashed(Element); +Element borderHeavy(Element); +Element borderDouble(Element); +Element borderRounded(Element); +Element borderEmpty(Element); +Decorator borderStyled(BorderStyle); +Decorator borderStyled(BorderStyle, Color); +Decorator borderStyled(Color); +Decorator borderWith(const Pixel&); +Element window(Element title, Element content, BorderStyle border = ROUNDED); +Element spinner(int charset_index, size_t image_index); +Element paragraph(const std::string& text); +Element paragraphAlignLeft(const std::string& text); +Element paragraphAlignRight(const std::string& text); +Element paragraphAlignCenter(const std::string& text); +Element paragraphAlignJustify(const std::string& text); +Element graph(GraphFunction); +Element emptyElement(); +Element canvas(ConstRef); +Element canvas(int width, int height, std::function); +Element canvas(std::function); + +// -- Decorator --- +Element bold(Element); +Element dim(Element); +Element inverted(Element); +Element underlined(Element); +Element underlinedDouble(Element); +Element blink(Element); +Element strikethrough(Element); +Decorator color(Color); +Decorator bgcolor(Color); +Decorator color(const LinearGradient&); +Decorator bgcolor(const LinearGradient&); +Element color(Color, Element); +Element bgcolor(Color, Element); +Element color(const LinearGradient&, Element); +Element bgcolor(const LinearGradient&, Element); +Decorator focusPosition(int x, int y); +Decorator focusPositionRelative(float x, float y); +Element automerge(Element child); +Decorator hyperlink(std::string link); +Element hyperlink(std::string link, Element child); +Element selectionStyleReset(Element); +Decorator selectionColor(Color foreground); +Decorator selectionBackgroundColor(Color foreground); +Decorator selectionForegroundColor(Color foreground); +Decorator selectionStyle(std::function style); + +// --- Layout is +// Horizontal, Vertical or stacked set of elements. +Element hbox(Elements); +Element vbox(Elements); +Element dbox(Elements); +Element flexbox(Elements, FlexboxConfig config = FlexboxConfig()); +Element gridbox(std::vector lines); + +Element hflow(Elements); // Helper: default flexbox with row direction. +Element vflow(Elements); // Helper: default flexbox with column direction. + +// -- Flexibility --- +// Define how to share the remaining space when not all of it is used inside a +// container. +Element flex(Element); // Expand/Minimize if possible/needed. +Element flex_grow(Element); // Expand element if possible. +Element flex_shrink(Element); // Minimize element if needed. + +Element xflex(Element); // Expand/Minimize if possible/needed on X axis. +Element xflex_grow(Element); // Expand element if possible on X axis. +Element xflex_shrink(Element); // Minimize element if needed on X axis. + +Element yflex(Element); // Expand/Minimize if possible/needed on Y axis. +Element yflex_grow(Element); // Expand element if possible on Y axis. +Element yflex_shrink(Element); // Minimize element if needed on Y axis. + +Element notflex(Element); // Reset the flex attribute. +Element filler(); // A blank expandable element. + +// -- Size override; +enum WidthOrHeight { WIDTH, HEIGHT }; +enum Constraint { LESS_THAN, EQUAL, GREATER_THAN }; +Decorator size(WidthOrHeight, Constraint, int value); + +// --- Frame --- +// A frame is a scrollable area. The internal area is potentially larger than +// the external one. The internal area is scrolled in order to make visible the +// focused element. +Element frame(Element); +Element xframe(Element); +Element yframe(Element); +Element focus(Element); +Element select(Element); + +// --- Cursor --- +// Those are similar to `focus`, but also change the shape of the cursor. +Element focusCursorBlock(Element); +Element focusCursorBlockBlinking(Element); +Element focusCursorBar(Element); +Element focusCursorBarBlinking(Element); +Element focusCursorUnderline(Element); +Element focusCursorUnderlineBlinking(Element); + +// --- Misc --- +Element vscroll_indicator(Element); +Element hscroll_indicator(Element); +Decorator reflect(Box& box); +// Before drawing the |element| clear the pixel below. This is useful in +// combinaison with dbox. +Element clear_under(Element element); + +// --- Util -------------------------------------------------------------------- +Element hcenter(Element); +Element vcenter(Element); +Element center(Element); +Element align_right(Element); +Element nothing(Element element); + +namespace Dimension { +Dimensions Fit(Element&, bool extend_beyond_screen = false); +} // namespace Dimension + +} // namespace ftxui + +// Make container able to take any number of children as input. +#include "ftxui/dom/take_any_args.hpp" + +// Include old definitions using wstring. +#include "ftxui/dom/deprecated.hpp" +#endif // FTXUI_DOM_ELEMENTS_HPP diff --git a/FTXUI/include/ftxui/dom/flexbox_config.hpp b/FTXUI/include/ftxui/dom/flexbox_config.hpp new file mode 100644 index 0000000..8ae2677 --- /dev/null +++ b/FTXUI/include/ftxui/dom/flexbox_config.hpp @@ -0,0 +1,114 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_FLEXBOX_CONFIG_HPP +#define FTXUI_DOM_FLEXBOX_CONFIG_HPP + +/* + This replicate the CSS flexbox model. + See guide for documentation: + https://css-tricks.com/snippets/css/a-guide-to-flexbox/ +*/ + +namespace ftxui { + +struct FlexboxConfig { + /// This establishes the main-axis, thus defining the direction flex items are + /// placed in the flex container. Flexbox is (aside wrapping) single-direction + /// layout concept. Think of flex items as primarily laying out either in + /// horizontal rows or vertical columns. + enum class Direction { + Row, ///< Flex items are laid out in a row. + RowInversed, ///< Flex items are laid out in a row, but in reverse order. + Column, ///< Flex items are laid out in a column. + ColumnInversed ///< Flex items are laid out in a column, but in reverse + ///< order. + }; + Direction direction = Direction::Row; + + /// By default, flex items will all try to fit onto one line. You can change + /// that and allow the items to wrap as needed with this property. + enum class Wrap { + NoWrap, ///< Flex items will all try to fit onto one line. + Wrap, ///< Flex items will wrap onto multiple lines. + WrapInversed, ///< Flex items will wrap onto multiple lines, but in reverse + ///< order. + }; + Wrap wrap = Wrap::Wrap; + + /// This defines the alignment along the main axis. It helps distribute extra + /// free space leftover when either all the flex items on a line are + /// inflexible, or are flexible but have reached their maximum size. It also + /// exerts some control over the alignment of items when they overflow the + /// line. + enum class JustifyContent { + /// Items are aligned to the start of flexbox's direction. + FlexStart, + /// Items are aligned to the end of flexbox's direction. + FlexEnd, + /// Items are centered along the line. + Center, + /// Items are stretched to fill the line. + Stretch, + /// Items are evenly distributed in the line; first item is on the start + // line, last item on the end line + SpaceBetween, + /// Items are evenly distributed in the line with equal space around them. + /// Note that visually the spaces aren’t equal, since all the items have + /// equal space on both sides. The first item will have one unit of space + /// against the container edge, but two units of space between the next item + /// because that next item has its own spacing that applies. + SpaceAround, + /// Items are distributed so that the spacing between any two items (and the + /// space to the edges) is equal. + SpaceEvenly, + }; + JustifyContent justify_content = JustifyContent::FlexStart; + + /// This defines the default behavior for how flex items are laid out along + /// the cross axis on the current line. Think of it as the justify-content + /// version for the cross-axis (perpendicular to the main-axis). + enum class AlignItems { + FlexStart, ///< items are placed at the start of the cross axis. + FlexEnd, ///< items are placed at the end of the cross axis. + Center, ///< items are centered along the cross axis. + Stretch, ///< items are stretched to fill the cross axis. + }; + AlignItems align_items = AlignItems::FlexStart; + + // This aligns a flex container’s lines within when there is extra space in + // the cross-axis, similar to how justify-content aligns individual items + // within the main-axis. + enum class AlignContent { + FlexStart, ///< items are placed at the start of the cross axis. + FlexEnd, ///< items are placed at the end of the cross axis. + Center, ///< items are centered along the cross axis. + Stretch, ///< items are stretched to fill the cross axis. + SpaceBetween, ///< items are evenly distributed in the cross axis. + SpaceAround, ///< tems evenly distributed with equal space around each + ///< line. + SpaceEvenly, ///< items are evenly distributed in the cross axis with equal + ///< space around them. + }; + AlignContent align_content = AlignContent::FlexStart; + + int gap_x = 0; + int gap_y = 0; + + // Constructor pattern. For chained use like: + // ``` + // FlexboxConfig() + // .Set(FlexboxConfig::Direction::Row) + // .Set(FlexboxConfig::Wrap::Wrap); + // ``` + FlexboxConfig& Set(FlexboxConfig::Direction); + FlexboxConfig& Set(FlexboxConfig::Wrap); + FlexboxConfig& Set(FlexboxConfig::JustifyContent); + FlexboxConfig& Set(FlexboxConfig::AlignItems); + FlexboxConfig& Set(FlexboxConfig::AlignContent); + FlexboxConfig& SetGap(int gap_x, int gap_y); +}; + +} // namespace ftxui + +#endif // FTXUI_DOM_FLEXBOX_CONFIG_HPP diff --git a/FTXUI/include/ftxui/dom/linear_gradient.hpp b/FTXUI/include/ftxui/dom/linear_gradient.hpp new file mode 100644 index 0000000..da7e77b --- /dev/null +++ b/FTXUI/include/ftxui/dom/linear_gradient.hpp @@ -0,0 +1,51 @@ +// Copyright 2023 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_LINEAR_GRADIENT_HPP +#define FTXUI_DOM_LINEAR_GRADIENT_HPP + +#include +#include + +#include "ftxui/screen/color.hpp" // for Colors + +namespace ftxui { + +/// @brief A class representing the settings for linear-gradient color effect. +/// +/// Example: +/// ```cpp +/// LinearGradient() +/// .Angle(45) +/// .Stop(Color::Red, 0.0) +/// .Stop(Color::Green, 0.5) +/// .Stop(Color::Blue, 1.0); +/// ``` +/// +/// There are also shorthand constructors: +/// ```cpp +/// LinearGradient(Color::Red, Color::Blue); +/// LinearGradient(45, Color::Red, Color::Blue); +/// ``` +struct LinearGradient { + float angle = 0.f; + struct Stop { + Color color = Color::Default; + std::optional position; + }; + std::vector stops; + + // Simple constructor + LinearGradient(); + LinearGradient(Color begin, Color end); + LinearGradient(float angle, Color begin, Color end); + + // Modifier using the builder pattern. + LinearGradient& Angle(float angle); + LinearGradient& Stop(Color color, float position); + LinearGradient& Stop(Color color); +}; + +} // namespace ftxui + +#endif // FTXUI_DOM_LINEAR_GRADIENT_HPP diff --git a/FTXUI/include/ftxui/dom/node.hpp b/FTXUI/include/ftxui/dom/node.hpp new file mode 100644 index 0000000..87edce7 --- /dev/null +++ b/FTXUI/include/ftxui/dom/node.hpp @@ -0,0 +1,77 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_NODE_HPP +#define FTXUI_DOM_NODE_HPP + +#include // for shared_ptr +#include // for vector + +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/dom/selection.hpp" // for Selection +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/screen.hpp" + +namespace ftxui { + +class Node; +class Screen; + +using Element = std::shared_ptr; +using Elements = std::vector; + +class Node { + public: + Node(); + explicit Node(Elements children); + Node(const Node&) = delete; + Node(const Node&&) = delete; + Node& operator=(const Node&) = delete; + Node& operator=(const Node&&) = delete; + + virtual ~Node(); + + // Step 1: Compute layout requirement. Tell parent what dimensions this + // element wants to be. + // Propagated from Children to Parents. + virtual void ComputeRequirement(); + Requirement requirement() { return requirement_; } + + // Step 2: Assign this element its final dimensions. + // Propagated from Parents to Children. + virtual void SetBox(Box box); + + // Step 3: (optional) Selection + // Propagated from Parents to Children. + virtual void Select(Selection& selection); + + // Step 4: Draw this element. + virtual void Render(Screen& screen); + + virtual std::string GetSelectedContent(Selection& selection); + + // Layout may not resolve within a single iteration for some elements. This + // allows them to request additionnal iterations. This signal must be + // forwarded to children at least once. + struct Status { + int iteration = 0; + bool need_iteration = false; + }; + virtual void Check(Status* status); + + protected: + Elements children_; + Requirement requirement_; + Box box_; +}; + +void Render(Screen& screen, const Element& element); +void Render(Screen& screen, Node* node); +void Render(Screen& screen, Node* node, Selection& selection); +std::string GetNodeSelectedContent(Screen& screen, + Node* node, + Selection& selection); + +} // namespace ftxui + +#endif // FTXUI_DOM_NODE_HPP diff --git a/FTXUI/include/ftxui/dom/requirement.hpp b/FTXUI/include/ftxui/dom/requirement.hpp new file mode 100644 index 0000000..1b0a884 --- /dev/null +++ b/FTXUI/include/ftxui/dom/requirement.hpp @@ -0,0 +1,34 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_REQUIREMENT_HPP +#define FTXUI_DOM_REQUIREMENT_HPP + +#include "ftxui/screen/box.hpp" + +namespace ftxui { + +struct Requirement { + // The required size to fully draw the element. + int min_x = 0; + int min_y = 0; + + // How much flexibility is given to the component. + int flex_grow_x = 0; + int flex_grow_y = 0; + int flex_shrink_x = 0; + int flex_shrink_y = 0; + + // Focus management to support the frame/focus/select element. + enum Selection { + NORMAL = 0, + SELECTED = 1, + FOCUSED = 2, + }; + Selection selection = NORMAL; + Box selected_box; +}; + +} // namespace ftxui + +#endif // FTXUI_DOM_REQUIREMENT_HPP diff --git a/FTXUI/include/ftxui/dom/selection.hpp b/FTXUI/include/ftxui/dom/selection.hpp new file mode 100644 index 0000000..912d9e4 --- /dev/null +++ b/FTXUI/include/ftxui/dom/selection.hpp @@ -0,0 +1,50 @@ +// Copyright 2024 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. + +#ifndef FTXUI_DOM_SELECTION_HPP +#define FTXUI_DOM_SELECTION_HPP + +#include + +#include +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/pixel.hpp" // for Pixel + +namespace ftxui { + +/// @brief Represent a selection in the terminal. +class Selection { + public: + Selection(); // Empty selection. + Selection(int start_x, int start_y, int end_x, int end_y); + + const Box& GetBox() const; + + Selection SaturateHorizontal(Box box); + Selection SaturateVertical(Box box); + bool IsEmpty() const { return empty_; } + + void AddPart(const std::string& part, int y, int left, int right); + std::string GetParts() { return parts_.str(); } + + private: + Selection(int start_x, int start_y, int end_x, int end_y, Selection* parent); + + const int start_x_ = 0; + const int start_y_ = 0; + const int end_x_ = 0; + const int end_y_ = 0; + const Box box_ = {}; + Selection* const parent_ = this; + const bool empty_ = true; + std::stringstream parts_; + + // The position of the last inserted part. + int x_ = 0; + int y_ = 0; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_DOM_SELECTION_HPP */ diff --git a/FTXUI/include/ftxui/dom/table.hpp b/FTXUI/include/ftxui/dom/table.hpp new file mode 100644 index 0000000..5460237 --- /dev/null +++ b/FTXUI/include/ftxui/dom/table.hpp @@ -0,0 +1,95 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_TABLE +#define FTXUI_DOM_TABLE + +#include // for string +#include // for vector + +#include "ftxui/dom/elements.hpp" // for Element, BorderStyle, LIGHT, Decorator + +namespace ftxui { + +// Usage: +// +// Initialization: +// --------------- +// +// auto table = Table({ +// {"X", "Y"}, +// {"-1", "1"}, +// {"+0", "0"}, +// {"+1", "1"}, +// }); +// +// table.SelectAll().Border(LIGHT); +// +// table.SelectRow(1).Border(DOUBLE); +// table.SelectRow(1).SeparatorInternal(Light); +// +// std::move(table).Element(); + +class Table; +class TableSelection; + +class Table { + public: + Table(); + explicit Table(std::vector>); + explicit Table(std::vector>); + Table(std::initializer_list> init); + TableSelection SelectAll(); + TableSelection SelectCell(int column, int row); + TableSelection SelectRow(int row_index); + TableSelection SelectRows(int row_min, int row_max); + TableSelection SelectColumn(int column_index); + TableSelection SelectColumns(int column_min, int column_max); + TableSelection SelectRectangle(int column_min, + int column_max, + int row_min, + int row_max); + Element Render(); + + private: + void Initialize(std::vector>); + friend TableSelection; + std::vector> elements_; + int input_dim_x_ = 0; + int input_dim_y_ = 0; + int dim_x_ = 0; + int dim_y_ = 0; +}; + +class TableSelection { + public: + void Decorate(Decorator); + void DecorateAlternateRow(Decorator, int modulo = 2, int shift = 0); + void DecorateAlternateColumn(Decorator, int modulo = 2, int shift = 0); + + void DecorateCells(Decorator); + void DecorateCellsAlternateColumn(Decorator, int modulo = 2, int shift = 0); + void DecorateCellsAlternateRow(Decorator, int modulo = 2, int shift = 0); + + void Border(BorderStyle border = LIGHT); + void BorderLeft(BorderStyle border = LIGHT); + void BorderRight(BorderStyle border = LIGHT); + void BorderTop(BorderStyle border = LIGHT); + void BorderBottom(BorderStyle border = LIGHT); + + void Separator(BorderStyle border = LIGHT); + void SeparatorVertical(BorderStyle border = LIGHT); + void SeparatorHorizontal(BorderStyle border = LIGHT); + + private: + friend Table; + Table* table_; + int x_min_; + int x_max_; + int y_min_; + int y_max_; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_DOM_TABLE */ diff --git a/FTXUI/include/ftxui/dom/take_any_args.hpp b/FTXUI/include/ftxui/dom/take_any_args.hpp new file mode 100644 index 0000000..52c8324 --- /dev/null +++ b/FTXUI/include/ftxui/dom/take_any_args.hpp @@ -0,0 +1,48 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_TAKE_ANY_ARGS_HPP +#define FTXUI_DOM_TAKE_ANY_ARGS_HPP + +// IWYU pragma: private, include "ftxui/dom/elements.hpp" +#include + +namespace ftxui { + +template +void Merge(Elements& /*container*/, T /*element*/) {} + +template <> +inline void Merge(Elements& container, Element element) { + container.push_back(std::move(element)); +} + +template <> +inline void Merge(Elements& container, Elements elements) { + for (auto& element : elements) { + container.push_back(std::move(element)); + } +} + +// Turn a set of arguments into a vector. +template +Elements unpack(Args... args) { + std::vector vec; + (Merge(vec, std::move(args)), ...); + return vec; +} + +// Make |container| able to take any number of argments. +#define TAKE_ANY_ARGS(container) \ + template \ + Element container(Args... children) { \ + return container(unpack(std::forward(children)...)); \ + } + +TAKE_ANY_ARGS(vbox) +TAKE_ANY_ARGS(hbox) +TAKE_ANY_ARGS(dbox) +TAKE_ANY_ARGS(hflow) +} // namespace ftxui + +#endif // FTXUI_DOM_TAKE_ANY_ARGS_HPP diff --git a/FTXUI/include/ftxui/screen/box.hpp b/FTXUI/include/ftxui/screen/box.hpp new file mode 100644 index 0000000..3770803 --- /dev/null +++ b/FTXUI/include/ftxui/screen/box.hpp @@ -0,0 +1,25 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_BOX_HPP +#define FTXUI_SCREEN_BOX_HPP + +namespace ftxui { + +struct Box { + int x_min = 0; + int x_max = 0; + int y_min = 0; + int y_max = 0; + + static auto Intersection(Box a, Box b) -> Box; + static auto Union(Box a, Box b) -> Box; + bool Contain(int x, int y) const; + bool IsEmpty() const; + bool operator==(const Box& other) const; + bool operator!=(const Box& other) const; +}; + +} // namespace ftxui + +#endif // FTXUI_SCREEN_BOX_HPP diff --git a/FTXUI/include/ftxui/screen/color.hpp b/FTXUI/include/ftxui/screen/color.hpp new file mode 100644 index 0000000..1489dca --- /dev/null +++ b/FTXUI/include/ftxui/screen/color.hpp @@ -0,0 +1,345 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_COLOR_HPP +#define FTXUI_SCREEN_COLOR_HPP + +#include // for uint8_t +#include // for string + +#ifdef RGB +// Workaround for wingdi.h (via Windows.h) defining macros that break things. +// https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-rgb +#undef RGB +#endif + +namespace ftxui { + +/// @brief A class representing terminal colors. +/// @ingroup screen +class Color { + public: + enum Palette1 : uint8_t; + enum Palette16 : uint8_t; + enum Palette256 : uint8_t; + + // NOLINTBEGIN + Color(); // Transparent. + Color(Palette1 index); // Transparent. + Color(Palette16 index); // Implicit conversion from index to Color. + Color(Palette256 index); // Implicit conversion from index to Color. + // NOLINTEND + Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255); + static Color RGB(uint8_t red, uint8_t green, uint8_t blue); + static Color HSV(uint8_t hue, uint8_t saturation, uint8_t value); + static Color RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); + static Color HSVA(uint8_t hue, + uint8_t saturation, + uint8_t value, + uint8_t alpha); + static Color Interpolate(float t, const Color& a, const Color& b); + static Color Blend(const Color& lhs, const Color& rhs); + + //--------------------------- + // List of colors: + //--------------------------- + // clang-format off + enum Palette1 : uint8_t{ + Default, // Transparent + }; + + enum Palette16 : uint8_t { + Black = 0, + Red = 1, + Green = 2, + Yellow = 3, + Blue = 4, + Magenta = 5, + Cyan = 6, + GrayLight = 7, + GrayDark = 8, + RedLight = 9, + GreenLight = 10, + YellowLight = 11, + BlueLight = 12, + MagentaLight = 13, + CyanLight = 14, + White = 15, + }; + + enum Palette256 : uint8_t { + Aquamarine1 = 122, + Aquamarine1Bis = 86, + Aquamarine3 = 79, + Blue1 = 21, + Blue3 = 19, + Blue3Bis = 20, + BlueViolet = 57, + CadetBlue = 72, + CadetBlueBis = 73, + Chartreuse1 = 118, + Chartreuse2 = 112, + Chartreuse2Bis = 82, + Chartreuse3 = 70, + Chartreuse3Bis = 76, + Chartreuse4 = 64, + CornflowerBlue = 69, + Cornsilk1 = 230, + Cyan1 = 51, + Cyan2 = 50, + Cyan3 = 43, + DarkBlue = 18, + DarkCyan = 36, + DarkGoldenrod = 136, + DarkGreen = 22, + DarkKhaki = 143, + DarkMagenta = 90, + DarkMagentaBis = 91, + DarkOliveGreen1 = 191, + DarkOliveGreen1Bis = 192, + DarkOliveGreen2 = 155, + DarkOliveGreen3 = 107, + DarkOliveGreen3Bis = 113, + DarkOliveGreen3Ter = 149, + DarkOrange = 208, + DarkOrange3 = 130, + DarkOrange3Bis = 166, + DarkRed = 52, + DarkRedBis = 88, + DarkSeaGreen = 108, + DarkSeaGreen1 = 158, + DarkSeaGreen1Bis = 193, + DarkSeaGreen2 = 151, + DarkSeaGreen2Bis = 157, + DarkSeaGreen3 = 115, + DarkSeaGreen3Bis = 150, + DarkSeaGreen4 = 65, + DarkSeaGreen4Bis = 71, + DarkSlateGray1 = 123, + DarkSlateGray2 = 87, + DarkSlateGray3 = 116, + DarkTurquoise = 44, + DarkViolet = 128, + DarkVioletBis = 92, + DeepPink1 = 198, + DeepPink1Bis = 199, + DeepPink2 = 197, + DeepPink3 = 161, + DeepPink3Bis = 162, + DeepPink4 = 125, + DeepPink4Bis = 89, + DeepPink4Ter = 53, + DeepSkyBlue1 = 39, + DeepSkyBlue2 = 38, + DeepSkyBlue3 = 31, + DeepSkyBlue3Bis = 32, + DeepSkyBlue4 = 23, + DeepSkyBlue4Bis = 24, + DeepSkyBlue4Ter = 25, + DodgerBlue1 = 33, + DodgerBlue2 = 27, + DodgerBlue3 = 26, + Gold1 = 220, + Gold3 = 142, + Gold3Bis = 178, + Green1 = 46, + Green3 = 34, + Green3Bis = 40, + Green4 = 28, + GreenYellow = 154, + Grey0 = 16, + Grey100 = 231, + Grey11 = 234, + Grey15 = 235, + Grey19 = 236, + Grey23 = 237, + Grey27 = 238, + Grey3 = 232, + Grey30 = 239, + Grey35 = 240, + Grey37 = 59, + Grey39 = 241, + Grey42 = 242, + Grey46 = 243, + Grey50 = 244, + Grey53 = 102, + Grey54 = 245, + Grey58 = 246, + Grey62 = 247, + Grey63 = 139, + Grey66 = 248, + Grey69 = 145, + Grey7 = 233, + Grey70 = 249, + Grey74 = 250, + Grey78 = 251, + Grey82 = 252, + Grey84 = 188, + Grey85 = 253, + Grey89 = 254, + Grey93 = 255, + Honeydew2 = 194, + HotPink = 205, + HotPink2 = 169, + HotPink3 = 132, + HotPink3Bis = 168, + HotPinkBis = 206, + IndianRed = 131, + IndianRed1 = 203, + IndianRed1Bis = 204, + IndianRedBis = 167, + Khaki1 = 228, + Khaki3 = 185, + LightCoral = 210, + LightCyan1Bis = 195, + LightCyan3 = 152, + LightGoldenrod1 = 227, + LightGoldenrod2 = 186, + LightGoldenrod2Bis = 221, + LightGoldenrod2Ter = 222, + LightGoldenrod3 = 179, + LightGreen = 119, + LightGreenBis = 120, + LightPink1 = 217, + LightPink3 = 174, + LightPink4 = 95, + LightSalmon1 = 216, + LightSalmon3 = 137, + LightSalmon3Bis = 173, + LightSeaGreen = 37, + LightSkyBlue1 = 153, + LightSkyBlue3 = 109, + LightSkyBlue3Bis = 110, + LightSlateBlue = 105, + LightSlateGrey = 103, + LightSteelBlue = 147, + LightSteelBlue1 = 189, + LightSteelBlue3 = 146, + LightYellow3 = 187, + Magenta1 = 201, + Magenta2 = 165, + Magenta2Bis = 200, + Magenta3 = 127, + Magenta3Bis = 163, + Magenta3Ter = 164, + MediumOrchid = 134, + MediumOrchid1 = 171, + MediumOrchid1Bis = 207, + MediumOrchid3 = 133, + MediumPurple = 104, + MediumPurple1 = 141, + MediumPurple2 = 135, + MediumPurple2Bis = 140, + MediumPurple3 = 97, + MediumPurple3Bis = 98, + MediumPurple4 = 60, + MediumSpringGreen = 49, + MediumTurquoise = 80, + MediumVioletRed = 126, + MistyRose1 = 224, + MistyRose3 = 181, + NavajoWhite1 = 223, + NavajoWhite3 = 144, + NavyBlue = 17, + Orange1 = 214, + Orange3 = 172, + Orange4 = 58, + Orange4Bis = 94, + OrangeRed1 = 202, + Orchid = 170, + Orchid1 = 213, + Orchid2 = 212, + PaleGreen1 = 121, + PaleGreen1Bis = 156, + PaleGreen3 = 114, + PaleGreen3Bis = 77, + PaleTurquoise1 = 159, + PaleTurquoise4 = 66, + PaleVioletRed1 = 211, + Pink1 = 218, + Pink3 = 175, + Plum1 = 219, + Plum2 = 183, + Plum3 = 176, + Plum4 = 96, + Purple = 129, + Purple3 = 56, + Purple4 = 54, + Purple4Bis = 55, + PurpleBis = 93, + Red1 = 196, + Red3 = 124, + Red3Bis = 160, + RosyBrown = 138, + RoyalBlue1 = 63, + Salmon1 = 209, + SandyBrown = 215, + SeaGreen1 = 84, + SeaGreen1Bis = 85, + SeaGreen2 = 83, + SeaGreen3 = 78, + SkyBlue1 = 117, + SkyBlue2 = 111, + SkyBlue3 = 74, + SlateBlue1 = 99, + SlateBlue3 = 61, + SlateBlue3Bis = 62, + SpringGreen1 = 48, + SpringGreen2 = 42, + SpringGreen2Bis = 47, + SpringGreen3 = 35, + SpringGreen3Bis = 41, + SpringGreen4 = 29, + SteelBlue = 67, + SteelBlue1 = 75, + SteelBlue1Bis = 81, + SteelBlue3 = 68, + Tan = 180, + Thistle1 = 225, + Thistle3 = 182, + Turquoise2 = 45, + Turquoise4 = 30, + Violet = 177, + Wheat1 = 229, + Wheat4 = 101, + Yellow1 = 226, + Yellow2 = 190, + Yellow3 = 148, + Yellow3Bis = 184, + Yellow4 = 100, + Yellow4Bis = 106, + }; + // clang-format on + + // --- Operators ------ + bool operator==(const Color& rhs) const; + bool operator!=(const Color& rhs) const; + + std::string Print(bool is_background_color) const; + bool IsOpaque() const { return alpha_ == 255; } + + private: + enum class ColorType : uint8_t { + Palette1, + Palette16, + Palette256, + TrueColor, + }; + ColorType type_ = ColorType::Palette1; + uint8_t red_ = 0; + uint8_t green_ = 0; + uint8_t blue_ = 0; + uint8_t alpha_ = 0; +}; + +inline namespace literals { + +/// @brief Creates a color from a combined hex RGB representation, +/// e.g. 0x808000_rgb +Color operator""_rgb(unsigned long long int combined); + +} // namespace literals + +} // namespace ftxui + +#endif // FTXUI_SCREEN_COLOR_HPP diff --git a/FTXUI/include/ftxui/screen/color_info.hpp b/FTXUI/include/ftxui/screen/color_info.hpp new file mode 100644 index 0000000..8e625e8 --- /dev/null +++ b/FTXUI/include/ftxui/screen/color_info.hpp @@ -0,0 +1,29 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_COLOR_INFO_HPP +#define FTXUI_SCREEN_COLOR_INFO_HPP + +#include +#include + +namespace ftxui { + +struct ColorInfo { + const char* name; + uint8_t index_256; + uint8_t index_16; + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t hue; + uint8_t saturation; + uint8_t value; +}; + +ColorInfo GetColorInfo(Color::Palette256 index); +ColorInfo GetColorInfo(Color::Palette16 index); + +} // namespace ftxui + +#endif // FTXUI_SCREEN_COLOR_INFO_HPP diff --git a/FTXUI/include/ftxui/screen/deprecated.hpp b/FTXUI/include/ftxui/screen/deprecated.hpp new file mode 100644 index 0000000..e3a51f8 --- /dev/null +++ b/FTXUI/include/ftxui/screen/deprecated.hpp @@ -0,0 +1,14 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_DEPRECATED_HPP +#define FTXUI_SCREEN_DEPRECATED_HPP + +#include + +namespace ftxui { +int wchar_width(wchar_t); +int wstring_width(const std::wstring&); +} // namespace ftxui + +#endif // FTXUI_SCREEN_DEPRECATED_HPP diff --git a/FTXUI/include/ftxui/screen/image.hpp b/FTXUI/include/ftxui/screen/image.hpp new file mode 100644 index 0000000..77e4719 --- /dev/null +++ b/FTXUI/include/ftxui/screen/image.hpp @@ -0,0 +1,48 @@ +// Copyright 2024 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_IMAGE_HPP +#define FTXUI_SCREEN_IMAGE_HPP + +#include // for string, basic_string, allocator +#include // for vector + +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/pixel.hpp" // for Pixel + +namespace ftxui { + +/// @brief A rectangular grid of Pixel. +/// @ingroup screen +class Image { + public: + // Constructors: + Image() = delete; + Image(int dimx, int dimy); + + // Access a character in the grid at a given position. + std::string& at(int x, int y); + const std::string& at(int x, int y) const; + + // Access a cell (Pixel) in the grid at a given position. + Pixel& PixelAt(int x, int y); + const Pixel& PixelAt(int x, int y) const; + + // Get screen dimensions. + int dimx() const { return dimx_; } + int dimy() const { return dimy_; } + + // Fill the image with space and default style + void Clear(); + + Box stencil; + + protected: + int dimx_; + int dimy_; + std::vector> pixels_; +}; + +} // namespace ftxui + +#endif // FTXUI_SCREEN_IMAGE_HPP diff --git a/FTXUI/include/ftxui/screen/pixel.hpp b/FTXUI/include/ftxui/screen/pixel.hpp new file mode 100644 index 0000000..cbc7cc2 --- /dev/null +++ b/FTXUI/include/ftxui/screen/pixel.hpp @@ -0,0 +1,52 @@ +// Copyright 2024 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_PIXEL_HPP +#define FTXUI_SCREEN_PIXEL_HPP + +#include // for uint8_t +#include // for string, basic_string, allocator +#include "ftxui/screen/color.hpp" // for Color, Color::Default + +namespace ftxui { + +/// @brief A Unicode character and its associated style. +/// @ingroup screen +struct Pixel { + Pixel() + : blink(false), + bold(false), + dim(false), + inverted(false), + underlined(false), + underlined_double(false), + strikethrough(false), + automerge(false) {} + + // A bit field representing the style: + bool blink : 1; + bool bold : 1; + bool dim : 1; + bool inverted : 1; + bool underlined : 1; + bool underlined_double : 1; + bool strikethrough : 1; + bool automerge : 1; + + // The hyperlink associated with the pixel. + // 0 is the default value, meaning no hyperlink. + // It's an index for accessing Screen meta data + uint8_t hyperlink = 0; + + // The graphemes stored into the pixel. To support combining characters, + // like: a?, this can potentially contain multiple codepoints. + std::string character = ""; + + // Colors: + Color background_color = Color::Default; + Color foreground_color = Color::Default; +}; + +} // namespace ftxui + +#endif // FTXUI_SCREEN_PIXEL_HPP diff --git a/FTXUI/include/ftxui/screen/screen.hpp b/FTXUI/include/ftxui/screen/screen.hpp new file mode 100644 index 0000000..aa2f4f8 --- /dev/null +++ b/FTXUI/include/ftxui/screen/screen.hpp @@ -0,0 +1,88 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_SCREEN_HPP +#define FTXUI_SCREEN_SCREEN_HPP + +#include // for uint8_t +#include // for function +#include // for string, basic_string, allocator +#include // for vector + +#include "ftxui/screen/image.hpp" // for Pixel, Image +#include "ftxui/screen/terminal.hpp" // for Dimensions +#include "ftxui/util/autoreset.hpp" // for AutoReset + +namespace ftxui { + +/// @brief Define how the Screen's dimensions should look like. +/// @ingroup screen +namespace Dimension { +Dimensions Fixed(int); +Dimensions Full(); +} // namespace Dimension + +/// @brief A rectangular grid of Pixel. +/// @ingroup screen +class Screen : public Image { + public: + // Constructors: + Screen(int dimx, int dimy); + static Screen Create(Dimensions dimension); + static Screen Create(Dimensions width, Dimensions height); + + std::string ToString() const; + + // Print the Screen on to the terminal. + void Print() const; + + // Fill the screen with space and reset any screen state, like hyperlinks, and + // cursor + void Clear(); + + // Move the terminal cursor n-lines up with n = dimy(). + std::string ResetPosition(bool clear = false) const; + + void ApplyShader(); + + struct Cursor { + int x = 0; + int y = 0; + + enum Shape { + Hidden = 0, + BlockBlinking = 1, + Block = 2, + UnderlineBlinking = 3, + Underline = 4, + BarBlinking = 5, + Bar = 6, + }; + Shape shape; + }; + + Cursor cursor() const { return cursor_; } + void SetCursor(Cursor cursor) { cursor_ = cursor; } + + // Store an hyperlink in the screen. Return the id of the hyperlink. The id is + // used to identify the hyperlink when the user click on it. + uint8_t RegisterHyperlink(const std::string& link); + const std::string& Hyperlink(uint8_t id) const; + + using SelectionStyle = std::function; + const SelectionStyle& GetSelectionStyle() const; + void SetSelectionStyle(SelectionStyle decorator); + + protected: + Cursor cursor_; + std::vector hyperlinks_ = {""}; + + // The current selection style. This is overridden by various dom elements. + SelectionStyle selection_style_ = [](Pixel& pixel) { + pixel.inverted ^= true; + }; +}; + +} // namespace ftxui + +#endif // FTXUI_SCREEN_SCREEN_HPP diff --git a/FTXUI/include/ftxui/screen/string.hpp b/FTXUI/include/ftxui/screen/string.hpp new file mode 100644 index 0000000..ca5397b --- /dev/null +++ b/FTXUI/include/ftxui/screen/string.hpp @@ -0,0 +1,31 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_STRING_HPP +#define FTXUI_SCREEN_STRING_HPP + +#include // for string, wstring, to_string +#include // for vector + +namespace ftxui { +std::string to_string(const std::wstring& s); +std::wstring to_wstring(const std::string& s); + +template +std::wstring to_wstring(T s) { + return to_wstring(std::to_string(s)); +} + +int string_width(const std::string&); + +// Split the string into a its glyphs. An empty one is inserted ater fullwidth +// ones. +std::vector Utf8ToGlyphs(const std::string& input); + +// Map every cells drawn by |input| to their corresponding Glyphs. Half-size +// Glyphs takes one cell, full-size Glyphs take two cells. +std::vector CellToGlyphIndex(const std::string& input); + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_SCREEN_STRING_HPP */ diff --git a/FTXUI/include/ftxui/screen/terminal.hpp b/FTXUI/include/ftxui/screen/terminal.hpp new file mode 100644 index 0000000..051aed0 --- /dev/null +++ b/FTXUI/include/ftxui/screen/terminal.hpp @@ -0,0 +1,30 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_TERMINAL_HPP +#define FTXUI_SCREEN_TERMINAL_HPP + +namespace ftxui { +struct Dimensions { + int dimx; + int dimy; +}; + +namespace Terminal { +Dimensions Size(); +void SetFallbackSize(const Dimensions& fallbackSize); + +enum Color { + Palette1, + Palette16, + Palette256, + TrueColor, +}; +Color ColorSupport(); +void SetColorSupport(Color color); + +} // namespace Terminal + +} // namespace ftxui + +#endif // FTXUI_SCREEN_TERMINAL_HPP diff --git a/FTXUI/include/ftxui/util/autoreset.hpp b/FTXUI/include/ftxui/util/autoreset.hpp new file mode 100644 index 0000000..ab33293 --- /dev/null +++ b/FTXUI/include/ftxui/util/autoreset.hpp @@ -0,0 +1,32 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_UTIL_AUTORESET_HPP +#define FTXUI_UTIL_AUTORESET_HPP + +#include + +namespace ftxui { + +/// Assign a value to a variable, reset its old value when going out of scope. +template +class AutoReset { + public: + AutoReset(T* variable, T new_value) + : variable_(variable), previous_value_(std::move(*variable)) { + *variable_ = std::move(new_value); + } + AutoReset(const AutoReset&) = delete; + AutoReset(AutoReset&&) = delete; + AutoReset& operator=(const AutoReset&) = delete; + AutoReset& operator=(AutoReset&&) = delete; + ~AutoReset() { *variable_ = std::move(previous_value_); } + + private: + T* variable_; + T previous_value_; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_UTIL_AUTORESET_HPP */ diff --git a/FTXUI/include/ftxui/util/ref.hpp b/FTXUI/include/ftxui/util/ref.hpp new file mode 100644 index 0000000..42a5938 --- /dev/null +++ b/FTXUI/include/ftxui/util/ref.hpp @@ -0,0 +1,216 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_UTIL_REF_HPP +#define FTXUI_UTIL_REF_HPP + +#include +#include +#include +#include +#include + +namespace ftxui { + +/// @brief An adapter. Own or reference an immutable object. +template +class ConstRef { + public: + ConstRef() = default; + ConstRef(T t) : variant_(std::move(t)) {} // NOLINT + ConstRef(const T* t) : variant_(t) {} // NOLINT + ConstRef& operator=(ConstRef&&) noexcept = default; + ConstRef(const ConstRef&) = default; + ConstRef(ConstRef&&) noexcept = default; + ~ConstRef() = default; + + // Make a "reseatable" reference + ConstRef& operator=(const ConstRef&) = default; + + // Accessors: + const T& operator()() const { return *Address(); } + const T& operator*() const { return *Address(); } + const T* operator->() const { return Address(); } + + private: + std::variant variant_ = T{}; + + const T* Address() const { + return std::holds_alternative(variant_) ? &std::get(variant_) + : std::get(variant_); + } +}; + +/// @brief An adapter. Own or reference an mutable object. +template +class Ref { + public: + Ref() = default; + Ref(T t) : variant_(std::move(t)) {} // NOLINT + Ref(T* t) : variant_(t) {} // NOLINT + ~Ref() = default; + Ref& operator=(Ref&&) noexcept = default; + Ref(const Ref&) = default; + Ref(Ref&&) noexcept = default; + + // Make a "reseatable" reference. + Ref& operator=(const Ref&) = default; + + // Accessors: + T& operator()() { return *Address(); } + T& operator*() { return *Address(); } + T* operator->() { return Address(); } + const T& operator()() const { return *Address(); } + const T& operator*() const { return *Address(); } + const T* operator->() const { return Address(); } + + private: + std::variant variant_ = T{}; + + const T* Address() const { + return std::holds_alternative(variant_) ? &std::get(variant_) + : std::get(variant_); + } + T* Address() { + return std::holds_alternative(variant_) ? &std::get(variant_) + : std::get(variant_); + } +}; + +/// @brief An adapter. Own or reference a constant string. For convenience, this +/// class convert multiple mutable string toward a shared representation. +class StringRef : public Ref { + public: + using Ref::Ref; + + StringRef(const wchar_t* ref) // NOLINT + : StringRef(to_string(std::wstring(ref))) {} + StringRef(const char* ref) // NOLINT + : StringRef(std::string(ref)) {} +}; + +/// @brief An adapter. Own or reference a constant string. For convenience, this +/// class convert multiple immutable string toward a shared representation. +class ConstStringRef : public ConstRef { + public: + using ConstRef::ConstRef; + + ConstStringRef(const std::wstring* ref) // NOLINT + : ConstStringRef(to_string(*ref)) {} + ConstStringRef(const std::wstring ref) // NOLINT + : ConstStringRef(to_string(ref)) {} + ConstStringRef(const wchar_t* ref) // NOLINT + : ConstStringRef(to_string(std::wstring(ref))) {} + ConstStringRef(const char* ref) // NOLINT + : ConstStringRef(std::string(ref)) {} +}; + +/// @brief An adapter. Reference a list of strings. +/// +/// Supported input: +/// - `std::vector` +/// - `std::vector*` +/// - `std::vector*` +/// - `Adapter*` +/// - `std::unique_ptr` +class ConstStringListRef { + public: + // Bring your own adapter: + class Adapter { + public: + Adapter() = default; + Adapter(const Adapter&) = default; + Adapter& operator=(const Adapter&) = default; + Adapter(Adapter&&) = default; + Adapter& operator=(Adapter&&) = default; + virtual ~Adapter() = default; + virtual size_t size() const = 0; + virtual std::string operator[](size_t i) const = 0; + }; + using Variant = std::variant, // + const std::vector*, // + const std::vector*, // + Adapter*, // + std::unique_ptr // + >; + + ConstStringListRef() = default; + ~ConstStringListRef() = default; + ConstStringListRef& operator=(const ConstStringListRef&) = default; + ConstStringListRef& operator=(ConstStringListRef&&) = default; + ConstStringListRef(ConstStringListRef&&) = default; + ConstStringListRef(const ConstStringListRef&) = default; + + ConstStringListRef(std::vector value) // NOLINT + { + variant_ = std::make_shared(value); + } + ConstStringListRef(const std::vector* value) // NOLINT + { + variant_ = std::make_shared(value); + } + ConstStringListRef(const std::vector* value) // NOLINT + { + variant_ = std::make_shared(value); + } + ConstStringListRef(Adapter* adapter) // NOLINT + { + variant_ = std::make_shared(adapter); + } + template + ConstStringListRef(std::unique_ptr adapter) // NOLINT + { + variant_ = std::make_shared( + static_cast>(std::move(adapter))); + } + + size_t size() const { + return variant_ ? std::visit(SizeVisitor(), *variant_) : 0; + } + + std::string operator[](size_t i) const { + return variant_ ? std::visit(IndexedGetter(i), *variant_) : ""; + } + + private: + struct SizeVisitor { + size_t operator()(const std::vector& v) const { + return v.size(); + } + size_t operator()(const std::vector* v) const { + return v->size(); + } + size_t operator()(const std::vector* v) const { + return v->size(); + } + size_t operator()(const Adapter* v) const { return v->size(); } + size_t operator()(const std::unique_ptr& v) const { + return v->size(); + } + }; + + struct IndexedGetter { + IndexedGetter(size_t index) // NOLINT + : index_(index) {} + size_t index_; + std::string operator()(const std::vector& v) const { + return v[index_]; + } + std::string operator()(const std::vector* v) const { + return (*v)[index_]; + } + std::string operator()(const std::vector* v) const { + return to_string((*v)[index_]); + } + std::string operator()(const Adapter* v) const { return (*v)[index_]; } + std::string operator()(const std::unique_ptr& v) const { + return (*v)[index_]; + } + }; + + std::shared_ptr variant_; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_UTIL_REF_HPP */ diff --git a/FTXUI/lib/Debug/ftxui-component.lib b/FTXUI/lib/Debug/ftxui-component.lib new file mode 100644 index 0000000..26766a6 Binary files /dev/null and b/FTXUI/lib/Debug/ftxui-component.lib differ diff --git a/FTXUI/lib/Debug/ftxui-component.pdb b/FTXUI/lib/Debug/ftxui-component.pdb new file mode 100644 index 0000000..253f82b Binary files /dev/null and b/FTXUI/lib/Debug/ftxui-component.pdb differ diff --git a/FTXUI/lib/Debug/ftxui-dom.lib b/FTXUI/lib/Debug/ftxui-dom.lib new file mode 100644 index 0000000..7aae4aa Binary files /dev/null and b/FTXUI/lib/Debug/ftxui-dom.lib differ diff --git a/FTXUI/lib/Debug/ftxui-dom.pdb b/FTXUI/lib/Debug/ftxui-dom.pdb new file mode 100644 index 0000000..527bcfa Binary files /dev/null and b/FTXUI/lib/Debug/ftxui-dom.pdb differ diff --git a/FTXUI/lib/Debug/ftxui-screen.lib b/FTXUI/lib/Debug/ftxui-screen.lib new file mode 100644 index 0000000..a28b1e8 Binary files /dev/null and b/FTXUI/lib/Debug/ftxui-screen.lib differ diff --git a/FTXUI/lib/Debug/ftxui-screen.pdb b/FTXUI/lib/Debug/ftxui-screen.pdb new file mode 100644 index 0000000..0a86b41 Binary files /dev/null and b/FTXUI/lib/Debug/ftxui-screen.pdb differ diff --git a/FTXUI/lib/cmake/ftxui/ftxui-config-version.cmake b/FTXUI/lib/cmake/ftxui/ftxui-config-version.cmake new file mode 100644 index 0000000..45ae348 --- /dev/null +++ b/FTXUI/lib/cmake/ftxui/ftxui-config-version.cmake @@ -0,0 +1,70 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version, +# but only if the requested major version is the same as the current one. +# The variable CVF_VERSION must be set before calling configure_file(). + + +set(PACKAGE_VERSION "5.0.0") + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + + if("5.0.0" MATCHES "^([0-9]+)\\.") + set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}") + if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}") + endif() + else() + set(CVF_VERSION_MAJOR "5.0.0") + endif() + + if(PACKAGE_FIND_VERSION_RANGE) + # both endpoints of the range must have the expected major version + math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1") + if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT))) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX))) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + else() + if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + endif() +endif() + + +# if the installed project requested no architecture check, don't perform the check +if("FALSE") + return() +endif() + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/FTXUI/lib/cmake/ftxui/ftxui-config.cmake b/FTXUI/lib/cmake/ftxui/ftxui-config.cmake new file mode 100644 index 0000000..73b6697 --- /dev/null +++ b/FTXUI/lib/cmake/ftxui/ftxui-config.cmake @@ -0,0 +1,30 @@ + +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +####### Any changes to this file will be overwritten by the next CMake run #### +####### The input file was ftxui-config.cmake.in ######## + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +macro(set_and_check _var _file) + set(${_var} "${_file}") + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") + endif() +endmacro() + +macro(check_required_components _NAME) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(NOT ${_NAME}_${comp}_FOUND) + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + endif() + endif() + endforeach() +endmacro() + +#################################################################################### + +include(CMakeFindDependencyMacro) +find_dependency(Threads) + +include("${CMAKE_CURRENT_LIST_DIR}/ftxui-targets.cmake") diff --git a/FTXUI/lib/cmake/ftxui/ftxui-targets-debug.cmake b/FTXUI/lib/cmake/ftxui/ftxui-targets-debug.cmake new file mode 100644 index 0000000..2ea5b1c --- /dev/null +++ b/FTXUI/lib/cmake/ftxui/ftxui-targets-debug.cmake @@ -0,0 +1,39 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Debug". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ftxui::screen" for configuration "Debug" +set_property(TARGET ftxui::screen APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) +set_target_properties(ftxui::screen PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/debug/ftxui-screen.lib" + ) + +list(APPEND _cmake_import_check_targets ftxui::screen ) +list(APPEND _cmake_import_check_files_for_ftxui::screen "${_IMPORT_PREFIX}/lib/debug/ftxui-screen.lib" ) + +# Import target "ftxui::dom" for configuration "Debug" +set_property(TARGET ftxui::dom APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) +set_target_properties(ftxui::dom PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/debug/ftxui-dom.lib" + ) + +list(APPEND _cmake_import_check_targets ftxui::dom ) +list(APPEND _cmake_import_check_files_for_ftxui::dom "${_IMPORT_PREFIX}/lib/debug/ftxui-dom.lib" ) + +# Import target "ftxui::component" for configuration "Debug" +set_property(TARGET ftxui::component APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) +set_target_properties(ftxui::component PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/debug/ftxui-component.lib" + ) + +list(APPEND _cmake_import_check_targets ftxui::component ) +list(APPEND _cmake_import_check_files_for_ftxui::component "${_IMPORT_PREFIX}/lib/debug/ftxui-component.lib" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/FTXUI/lib/cmake/ftxui/ftxui-targets-release.cmake b/FTXUI/lib/cmake/ftxui/ftxui-targets-release.cmake new file mode 100644 index 0000000..2799677 --- /dev/null +++ b/FTXUI/lib/cmake/ftxui/ftxui-targets-release.cmake @@ -0,0 +1,39 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ftxui::screen" for configuration "Release" +set_property(TARGET ftxui::screen APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ftxui::screen PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/ftxui-screen.lib" + ) + +list(APPEND _cmake_import_check_targets ftxui::screen ) +list(APPEND _cmake_import_check_files_for_ftxui::screen "${_IMPORT_PREFIX}/lib/ftxui-screen.lib" ) + +# Import target "ftxui::dom" for configuration "Release" +set_property(TARGET ftxui::dom APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ftxui::dom PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/ftxui-dom.lib" + ) + +list(APPEND _cmake_import_check_targets ftxui::dom ) +list(APPEND _cmake_import_check_files_for_ftxui::dom "${_IMPORT_PREFIX}/lib/ftxui-dom.lib" ) + +# Import target "ftxui::component" for configuration "Release" +set_property(TARGET ftxui::component APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ftxui::component PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/ftxui-component.lib" + ) + +list(APPEND _cmake_import_check_targets ftxui::component ) +list(APPEND _cmake_import_check_files_for_ftxui::component "${_IMPORT_PREFIX}/lib/ftxui-component.lib" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/FTXUI/lib/cmake/ftxui/ftxui-targets.cmake b/FTXUI/lib/cmake/ftxui/ftxui-targets.cmake new file mode 100644 index 0000000..aac5b8a --- /dev/null +++ b/FTXUI/lib/cmake/ftxui/ftxui-targets.cmake @@ -0,0 +1,131 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.23) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS ftxui::screen ftxui::dom ftxui::component) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target ftxui::screen +add_library(ftxui::screen STATIC IMPORTED) + +set_target_properties(ftxui::screen PROPERTIES + INTERFACE_COMPILE_FEATURES "cxx_std_17" + INTERFACE_COMPILE_OPTIONS "/utf-8" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "include" +) + +# Create imported target ftxui::dom +add_library(ftxui::dom STATIC IMPORTED) + +set_target_properties(ftxui::dom PROPERTIES + INTERFACE_COMPILE_FEATURES "cxx_std_17" + INTERFACE_COMPILE_OPTIONS "/utf-8" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" + INTERFACE_LINK_LIBRARIES "ftxui::screen" + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "include" +) + +# Create imported target ftxui::component +add_library(ftxui::component STATIC IMPORTED) + +set_target_properties(ftxui::component PROPERTIES + INTERFACE_COMPILE_FEATURES "cxx_std_17" + INTERFACE_COMPILE_OPTIONS "/utf-8" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" + INTERFACE_LINK_LIBRARIES "ftxui::dom;Threads::Threads" + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "include" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ftxui-targets-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/FTXUI/lib/ftxui-component.lib b/FTXUI/lib/ftxui-component.lib new file mode 100644 index 0000000..2b98723 Binary files /dev/null and b/FTXUI/lib/ftxui-component.lib differ diff --git a/FTXUI/lib/ftxui-dom.lib b/FTXUI/lib/ftxui-dom.lib new file mode 100644 index 0000000..f1e4412 Binary files /dev/null and b/FTXUI/lib/ftxui-dom.lib differ diff --git a/FTXUI/lib/ftxui-screen.lib b/FTXUI/lib/ftxui-screen.lib new file mode 100644 index 0000000..6ad99b6 Binary files /dev/null and b/FTXUI/lib/ftxui-screen.lib differ diff --git a/FTXUI/lib/pkgconfig/ftxui.pc b/FTXUI/lib/pkgconfig/ftxui.pc new file mode 100644 index 0000000..f7c625f --- /dev/null +++ b/FTXUI/lib/pkgconfig/ftxui.pc @@ -0,0 +1,9 @@ +prefix="C:/Program Files (x86)/ftxui" +libdir="C:/Program Files (x86)/ftxui/lib" +includedir="C:/Program Files (x86)/ftxui/include" + +Name: ftxui +Description: C++ Functional Terminal User Interface. +Version: 5.0.0 +Cflags: -I${includedir} +Libs: -L${libdir} -lftxui-component -lftxui-dom -lftxui-screen diff --git a/GTest/include/gmock/gmock-actions.h b/GTest/include/gmock/gmock-actions.h new file mode 100644 index 0000000..aa47079 --- /dev/null +++ b/GTest/include/gmock/gmock-actions.h @@ -0,0 +1,2360 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// The ACTION* family of macros can be used in a namespace scope to +// define custom actions easily. The syntax: +// +// ACTION(name) { statements; } +// +// will define an action with the given name that executes the +// statements. The value returned by the statements will be used as +// the return value of the action. Inside the statements, you can +// refer to the K-th (0-based) argument of the mock function by +// 'argK', and refer to its type by 'argK_type'. For example: +// +// ACTION(IncrementArg1) { +// arg1_type temp = arg1; +// return ++(*temp); +// } +// +// allows you to write +// +// ...WillOnce(IncrementArg1()); +// +// You can also refer to the entire argument tuple and its type by +// 'args' and 'args_type', and refer to the mock function type and its +// return type by 'function_type' and 'return_type'. +// +// Note that you don't need to specify the types of the mock function +// arguments. However rest assured that your code is still type-safe: +// you'll get a compiler error if *arg1 doesn't support the ++ +// operator, or if the type of ++(*arg1) isn't compatible with the +// mock function's return type, for example. +// +// Sometimes you'll want to parameterize the action. For that you can use +// another macro: +// +// ACTION_P(name, param_name) { statements; } +// +// For example: +// +// ACTION_P(Add, n) { return arg0 + n; } +// +// will allow you to write: +// +// ...WillOnce(Add(5)); +// +// Note that you don't need to provide the type of the parameter +// either. If you need to reference the type of a parameter named +// 'foo', you can write 'foo_type'. For example, in the body of +// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type +// of 'n'. +// +// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support +// multi-parameter actions. +// +// For the purpose of typing, you can view +// +// ACTION_Pk(Foo, p1, ..., pk) { ... } +// +// as shorthand for +// +// template +// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } +// +// In particular, you can provide the template type arguments +// explicitly when invoking Foo(), as in Foo(5, false); +// although usually you can rely on the compiler to infer the types +// for you automatically. You can assign the result of expression +// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. +// +// You can also overload actions with different numbers of parameters: +// +// ACTION_P(Plus, a) { ... } +// ACTION_P2(Plus, a, b) { ... } +// +// While it's tempting to always use the ACTION* macros when defining +// a new action, you should also consider implementing ActionInterface +// or using MakePolymorphicAction() instead, especially if you need to +// use the action a lot. While these approaches require more work, +// they give you more control on the types of the mock function +// arguments and the action parameters, which in general leads to +// better compiler error messages that pay off in the long run. They +// also allow overloading actions based on parameter types (as opposed +// to just based on the number of parameters). +// +// CAVEAT: +// +// ACTION*() can only be used in a namespace scope as templates cannot be +// declared inside of a local class. +// Users can, however, define any local functors (e.g. a lambda) that +// can be used as actions. +// +// MORE INFORMATION: +// +// To learn more about using these macros, please search for 'ACTION' on +// https://github.com/google/googletest/blob/main/docs/gmock_cook_book.md + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ + +#ifndef _WIN32_WCE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" +#include "gmock/internal/gmock-pp.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4100) + +namespace testing { + +// To implement an action Foo, define: +// 1. a class FooAction that implements the ActionInterface interface, and +// 2. a factory function that creates an Action object from a +// const FooAction*. +// +// The two-level delegation design follows that of Matcher, providing +// consistency for extension developers. It also eases ownership +// management as Action objects can now be copied like plain values. + +namespace internal { + +// BuiltInDefaultValueGetter::Get() returns a +// default-constructed T value. BuiltInDefaultValueGetter::Get() crashes with an error. +// +// This primary template is used when kDefaultConstructible is true. +template +struct BuiltInDefaultValueGetter { + static T Get() { return T(); } +}; +template +struct BuiltInDefaultValueGetter { + static T Get() { + Assert(false, __FILE__, __LINE__, + "Default action undefined for the function return type."); +#if defined(__GNUC__) || defined(__clang__) + __builtin_unreachable(); +#elif defined(_MSC_VER) + __assume(0); +#else + return Invalid(); + // The above statement will never be reached, but is required in + // order for this function to compile. +#endif + } +}; + +// BuiltInDefaultValue::Get() returns the "built-in" default value +// for type T, which is NULL when T is a raw pointer type, 0 when T is +// a numeric type, false when T is bool, or "" when T is string or +// std::string. In addition, in C++11 and above, it turns a +// default-constructed T value if T is default constructible. For any +// other type T, the built-in default T value is undefined, and the +// function will abort the process. +template +class BuiltInDefaultValue { + public: + // This function returns true if and only if type T has a built-in default + // value. + static bool Exists() { return ::std::is_default_constructible::value; } + + static T Get() { + return BuiltInDefaultValueGetter< + T, ::std::is_default_constructible::value>::Get(); + } +}; + +// This partial specialization says that we use the same built-in +// default value for T and const T. +template +class BuiltInDefaultValue { + public: + static bool Exists() { return BuiltInDefaultValue::Exists(); } + static T Get() { return BuiltInDefaultValue::Get(); } +}; + +// This partial specialization defines the default values for pointer +// types. +template +class BuiltInDefaultValue { + public: + static bool Exists() { return true; } + static T* Get() { return nullptr; } +}; + +// The following specializations define the default values for +// specific types we care about. +#define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \ + template <> \ + class BuiltInDefaultValue { \ + public: \ + static bool Exists() { return true; } \ + static type Get() { return value; } \ + } + +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0'); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed char, '\0'); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(char, '\0'); + +// There's no need for a default action for signed wchar_t, as that +// type is the same as wchar_t for gcc, and invalid for MSVC. +// +// There's also no need for a default action for unsigned wchar_t, as +// that type is the same as unsigned int for gcc, and invalid for +// MSVC. +#if GMOCK_WCHAR_T_IS_NATIVE_ +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT +#endif + +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned short, 0U); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed short, 0); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned int, 0U); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long long, 0); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long long, 0); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0); + +#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ + +// Partial implementations of metaprogramming types from the standard library +// not available in C++11. + +template +struct negation + // NOLINTNEXTLINE + : std::integral_constant {}; + +// Base case: with zero predicates the answer is always true. +template +struct conjunction : std::true_type {}; + +// With a single predicate, the answer is that predicate. +template +struct conjunction : P1 {}; + +// With multiple predicates the answer is the first predicate if that is false, +// and we recurse otherwise. +template +struct conjunction + : std::conditional, P1>::type {}; + +template +struct disjunction : std::false_type {}; + +template +struct disjunction : P1 {}; + +template +struct disjunction + // NOLINTNEXTLINE + : std::conditional, P1>::type {}; + +template +using void_t = void; + +// Detects whether an expression of type `From` can be implicitly converted to +// `To` according to [conv]. In C++17, [conv]/3 defines this as follows: +// +// An expression e can be implicitly converted to a type T if and only if +// the declaration T t=e; is well-formed, for some invented temporary +// variable t ([dcl.init]). +// +// [conv]/2 implies we can use function argument passing to detect whether this +// initialization is valid. +// +// Note that this is distinct from is_convertible, which requires this be valid: +// +// To test() { +// return declval(); +// } +// +// In particular, is_convertible doesn't give the correct answer when `To` and +// `From` are the same non-moveable type since `declval` will be an rvalue +// reference, defeating the guaranteed copy elision that would otherwise make +// this function work. +// +// REQUIRES: `From` is not cv void. +template +struct is_implicitly_convertible { + private: + // A function that accepts a parameter of type T. This can be called with type + // U successfully only if U is implicitly convertible to T. + template + static void Accept(T); + + // A function that creates a value of type T. + template + static T Make(); + + // An overload be selected when implicit conversion from T to To is possible. + template (Make()))> + static std::true_type TestImplicitConversion(int); + + // A fallback overload selected in all other cases. + template + static std::false_type TestImplicitConversion(...); + + public: + using type = decltype(TestImplicitConversion(0)); + static constexpr bool value = type::value; +}; + +// Like std::invoke_result_t from C++17, but works only for objects with call +// operators (not e.g. member function pointers, which we don't need specific +// support for in OnceAction because std::function deals with them). +template +using call_result_t = decltype(std::declval()(std::declval()...)); + +template +struct is_callable_r_impl : std::false_type {}; + +// Specialize the struct for those template arguments where call_result_t is +// well-formed. When it's not, the generic template above is chosen, resulting +// in std::false_type. +template +struct is_callable_r_impl>, R, F, Args...> + : std::conditional< + std::is_void::value, // + std::true_type, // + is_implicitly_convertible, R>>::type {}; + +// Like std::is_invocable_r from C++17, but works only for objects with call +// operators. See the note on call_result_t. +template +using is_callable_r = is_callable_r_impl; + +// Like std::as_const from C++17. +template +typename std::add_const::type& as_const(T& t) { + return t; +} + +} // namespace internal + +// Specialized for function types below. +template +class OnceAction; + +// An action that can only be used once. +// +// This is accepted by WillOnce, which doesn't require the underlying action to +// be copy-constructible (only move-constructible), and promises to invoke it as +// an rvalue reference. This allows the action to work with move-only types like +// std::move_only_function in a type-safe manner. +// +// For example: +// +// // Assume we have some API that needs to accept a unique pointer to some +// // non-copyable object Foo. +// void AcceptUniquePointer(std::unique_ptr foo); +// +// // We can define an action that provides a Foo to that API. Because It +// // has to give away its unique pointer, it must not be called more than +// // once, so its call operator is &&-qualified. +// struct ProvideFoo { +// std::unique_ptr foo; +// +// void operator()() && { +// AcceptUniquePointer(std::move(Foo)); +// } +// }; +// +// // This action can be used with WillOnce. +// EXPECT_CALL(mock, Call) +// .WillOnce(ProvideFoo{std::make_unique(...)}); +// +// // But a call to WillRepeatedly will fail to compile. This is correct, +// // since the action cannot correctly be used repeatedly. +// EXPECT_CALL(mock, Call) +// .WillRepeatedly(ProvideFoo{std::make_unique(...)}); +// +// A less-contrived example would be an action that returns an arbitrary type, +// whose &&-qualified call operator is capable of dealing with move-only types. +template +class OnceAction final { + private: + // True iff we can use the given callable type (or lvalue reference) directly + // via StdFunctionAdaptor. + template + using IsDirectlyCompatible = internal::conjunction< + // It must be possible to capture the callable in StdFunctionAdaptor. + std::is_constructible::type, Callable>, + // The callable must be compatible with our signature. + internal::is_callable_r::type, + Args...>>; + + // True iff we can use the given callable type via StdFunctionAdaptor once we + // ignore incoming arguments. + template + using IsCompatibleAfterIgnoringArguments = internal::conjunction< + // It must be possible to capture the callable in a lambda. + std::is_constructible::type, Callable>, + // The callable must be invocable with zero arguments, returning something + // convertible to Result. + internal::is_callable_r::type>>; + + public: + // Construct from a callable that is directly compatible with our mocked + // signature: it accepts our function type's arguments and returns something + // convertible to our result type. + template ::type>>, + IsDirectlyCompatible> // + ::value, + int>::type = 0> + OnceAction(Callable&& callable) // NOLINT + : function_(StdFunctionAdaptor::type>( + {}, std::forward(callable))) {} + + // As above, but for a callable that ignores the mocked function's arguments. + template ::type>>, + // Exclude callables for which the overload above works. + // We'd rather provide the arguments if possible. + internal::negation>, + IsCompatibleAfterIgnoringArguments>::value, + int>::type = 0> + OnceAction(Callable&& callable) // NOLINT + // Call the constructor above with a callable + // that ignores the input arguments. + : OnceAction(IgnoreIncomingArguments::type>{ + std::forward(callable)}) {} + + // We are naturally copyable because we store only an std::function, but + // semantically we should not be copyable. + OnceAction(const OnceAction&) = delete; + OnceAction& operator=(const OnceAction&) = delete; + OnceAction(OnceAction&&) = default; + + // Invoke the underlying action callable with which we were constructed, + // handing it the supplied arguments. + Result Call(Args... args) && { + return function_(std::forward(args)...); + } + + private: + // An adaptor that wraps a callable that is compatible with our signature and + // being invoked as an rvalue reference so that it can be used as an + // StdFunctionAdaptor. This throws away type safety, but that's fine because + // this is only used by WillOnce, which we know calls at most once. + // + // Once we have something like std::move_only_function from C++23, we can do + // away with this. + template + class StdFunctionAdaptor final { + public: + // A tag indicating that the (otherwise universal) constructor is accepting + // the callable itself, instead of e.g. stealing calls for the move + // constructor. + struct CallableTag final {}; + + template + explicit StdFunctionAdaptor(CallableTag, F&& callable) + : callable_(std::make_shared(std::forward(callable))) {} + + // Rather than explicitly returning Result, we return whatever the wrapped + // callable returns. This allows for compatibility with existing uses like + // the following, when the mocked function returns void: + // + // EXPECT_CALL(mock_fn_, Call) + // .WillOnce([&] { + // [...] + // return 0; + // }); + // + // Such a callable can be turned into std::function. If we use an + // explicit return type of Result here then it *doesn't* work with + // std::function, because we'll get a "void function should not return a + // value" error. + // + // We need not worry about incompatible result types because the SFINAE on + // OnceAction already checks this for us. std::is_invocable_r_v itself makes + // the same allowance for void result types. + template + internal::call_result_t operator()( + ArgRefs&&... args) const { + return std::move(*callable_)(std::forward(args)...); + } + + private: + // We must put the callable on the heap so that we are copyable, which + // std::function needs. + std::shared_ptr callable_; + }; + + // An adaptor that makes a callable that accepts zero arguments callable with + // our mocked arguments. + template + struct IgnoreIncomingArguments { + internal::call_result_t operator()(Args&&...) { + return std::move(callable)(); + } + + Callable callable; + }; + + std::function function_; +}; + +// When an unexpected function call is encountered, Google Mock will +// let it return a default value if the user has specified one for its +// return type, or if the return type has a built-in default value; +// otherwise Google Mock won't know what value to return and will have +// to abort the process. +// +// The DefaultValue class allows a user to specify the +// default value for a type T that is both copyable and publicly +// destructible (i.e. anything that can be used as a function return +// type). The usage is: +// +// // Sets the default value for type T to be foo. +// DefaultValue::Set(foo); +template +class DefaultValue { + public: + // Sets the default value for type T; requires T to be + // copy-constructable and have a public destructor. + static void Set(T x) { + delete producer_; + producer_ = new FixedValueProducer(x); + } + + // Provides a factory function to be called to generate the default value. + // This method can be used even if T is only move-constructible, but it is not + // limited to that case. + typedef T (*FactoryFunction)(); + static void SetFactory(FactoryFunction factory) { + delete producer_; + producer_ = new FactoryValueProducer(factory); + } + + // Unsets the default value for type T. + static void Clear() { + delete producer_; + producer_ = nullptr; + } + + // Returns true if and only if the user has set the default value for type T. + static bool IsSet() { return producer_ != nullptr; } + + // Returns true if T has a default return value set by the user or there + // exists a built-in default value. + static bool Exists() { + return IsSet() || internal::BuiltInDefaultValue::Exists(); + } + + // Returns the default value for type T if the user has set one; + // otherwise returns the built-in default value. Requires that Exists() + // is true, which ensures that the return value is well-defined. + static T Get() { + return producer_ == nullptr ? internal::BuiltInDefaultValue::Get() + : producer_->Produce(); + } + + private: + class ValueProducer { + public: + virtual ~ValueProducer() = default; + virtual T Produce() = 0; + }; + + class FixedValueProducer : public ValueProducer { + public: + explicit FixedValueProducer(T value) : value_(value) {} + T Produce() override { return value_; } + + private: + const T value_; + FixedValueProducer(const FixedValueProducer&) = delete; + FixedValueProducer& operator=(const FixedValueProducer&) = delete; + }; + + class FactoryValueProducer : public ValueProducer { + public: + explicit FactoryValueProducer(FactoryFunction factory) + : factory_(factory) {} + T Produce() override { return factory_(); } + + private: + const FactoryFunction factory_; + FactoryValueProducer(const FactoryValueProducer&) = delete; + FactoryValueProducer& operator=(const FactoryValueProducer&) = delete; + }; + + static ValueProducer* producer_; +}; + +// This partial specialization allows a user to set default values for +// reference types. +template +class DefaultValue { + public: + // Sets the default value for type T&. + static void Set(T& x) { // NOLINT + address_ = &x; + } + + // Unsets the default value for type T&. + static void Clear() { address_ = nullptr; } + + // Returns true if and only if the user has set the default value for type T&. + static bool IsSet() { return address_ != nullptr; } + + // Returns true if T has a default return value set by the user or there + // exists a built-in default value. + static bool Exists() { + return IsSet() || internal::BuiltInDefaultValue::Exists(); + } + + // Returns the default value for type T& if the user has set one; + // otherwise returns the built-in default value if there is one; + // otherwise aborts the process. + static T& Get() { + return address_ == nullptr ? internal::BuiltInDefaultValue::Get() + : *address_; + } + + private: + static T* address_; +}; + +// This specialization allows DefaultValue::Get() to +// compile. +template <> +class DefaultValue { + public: + static bool Exists() { return true; } + static void Get() {} +}; + +// Points to the user-set default value for type T. +template +typename DefaultValue::ValueProducer* DefaultValue::producer_ = nullptr; + +// Points to the user-set default value for type T&. +template +T* DefaultValue::address_ = nullptr; + +// Implement this interface to define an action for function type F. +template +class ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + ActionInterface() = default; + virtual ~ActionInterface() = default; + + // Performs the action. This method is not const, as in general an + // action can have side effects and be stateful. For example, a + // get-the-next-element-from-the-collection action will need to + // remember the current element. + virtual Result Perform(const ArgumentTuple& args) = 0; + + private: + ActionInterface(const ActionInterface&) = delete; + ActionInterface& operator=(const ActionInterface&) = delete; +}; + +template +class Action; + +// An Action is a copyable and IMMUTABLE (except by assignment) +// object that represents an action to be taken when a mock function of type +// R(Args...) is called. The implementation of Action is just a +// std::shared_ptr to const ActionInterface. Don't inherit from Action! You +// can view an object implementing ActionInterface as a concrete action +// (including its current state), and an Action object as a handle to it. +template +class Action { + private: + using F = R(Args...); + + // Adapter class to allow constructing Action from a legacy ActionInterface. + // New code should create Actions from functors instead. + struct ActionAdapter { + // Adapter must be copyable to satisfy std::function requirements. + ::std::shared_ptr> impl_; + + template + typename internal::Function::Result operator()(InArgs&&... args) { + return impl_->Perform( + ::std::forward_as_tuple(::std::forward(args)...)); + } + }; + + template + using IsCompatibleFunctor = std::is_constructible, G>; + + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + // Constructs a null Action. Needed for storing Action objects in + // STL containers. + Action() = default; + + // Construct an Action from a specified callable. + // This cannot take std::function directly, because then Action would not be + // directly constructible from lambda (it would require two conversions). + template < + typename G, + typename = typename std::enable_if, std::is_constructible, + G>>::value>::type> + Action(G&& fun) { // NOLINT + Init(::std::forward(fun), IsCompatibleFunctor()); + } + + // Constructs an Action from its implementation. + explicit Action(ActionInterface* impl) + : fun_(ActionAdapter{::std::shared_ptr>(impl)}) {} + + // This constructor allows us to turn an Action object into an + // Action, as long as F's arguments can be implicitly converted + // to Func's and Func's return type can be implicitly converted to F's. + template + Action(const Action& action) // NOLINT + : fun_(action.fun_) {} + + // Returns true if and only if this is the DoDefault() action. + bool IsDoDefault() const { return fun_ == nullptr; } + + // Performs the action. Note that this method is const even though + // the corresponding method in ActionInterface is not. The reason + // is that a const Action means that it cannot be re-bound to + // another concrete action, not that the concrete action it binds to + // cannot change state. (Think of the difference between a const + // pointer and a pointer to const.) + Result Perform(ArgumentTuple args) const { + if (IsDoDefault()) { + internal::IllegalDoDefault(__FILE__, __LINE__); + } + return internal::Apply(fun_, ::std::move(args)); + } + + // An action can be used as a OnceAction, since it's obviously safe to call it + // once. + operator OnceAction() const { // NOLINT + // Return a OnceAction-compatible callable that calls Perform with the + // arguments it is provided. We could instead just return fun_, but then + // we'd need to handle the IsDoDefault() case separately. + struct OA { + Action action; + + R operator()(Args... args) && { + return action.Perform( + std::forward_as_tuple(std::forward(args)...)); + } + }; + + return OA{*this}; + } + + private: + template + friend class Action; + + template + void Init(G&& g, ::std::true_type) { + fun_ = ::std::forward(g); + } + + template + void Init(G&& g, ::std::false_type) { + fun_ = IgnoreArgs::type>{::std::forward(g)}; + } + + template + struct IgnoreArgs { + template + Result operator()(const InArgs&...) const { + return function_impl(); + } + + FunctionImpl function_impl; + }; + + // fun_ is an empty function if and only if this is the DoDefault() action. + ::std::function fun_; +}; + +// The PolymorphicAction class template makes it easy to implement a +// polymorphic action (i.e. an action that can be used in mock +// functions of than one type, e.g. Return()). +// +// To define a polymorphic action, a user first provides a COPYABLE +// implementation class that has a Perform() method template: +// +// class FooAction { +// public: +// template +// Result Perform(const ArgumentTuple& args) const { +// // Processes the arguments and returns a result, using +// // std::get(args) to get the N-th (0-based) argument in the tuple. +// } +// ... +// }; +// +// Then the user creates the polymorphic action using +// MakePolymorphicAction(object) where object has type FooAction. See +// the definition of Return(void) and SetArgumentPointee(value) for +// complete examples. +template +class PolymorphicAction { + public: + explicit PolymorphicAction(const Impl& impl) : impl_(impl) {} + + template + operator Action() const { + return Action(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + Result Perform(const ArgumentTuple& args) override { + return impl_.template Perform(args); + } + + private: + Impl impl_; + }; + + Impl impl_; +}; + +// Creates an Action from its implementation and returns it. The +// created Action object owns the implementation. +template +Action MakeAction(ActionInterface* impl) { + return Action(impl); +} + +// Creates a polymorphic action from its implementation. This is +// easier to use than the PolymorphicAction constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicAction(foo); +// vs +// PolymorphicAction(foo); +template +inline PolymorphicAction MakePolymorphicAction(const Impl& impl) { + return PolymorphicAction(impl); +} + +namespace internal { + +// Helper struct to specialize ReturnAction to execute a move instead of a copy +// on return. Useful for move-only types, but could be used on any type. +template +struct ByMoveWrapper { + explicit ByMoveWrapper(T value) : payload(std::move(value)) {} + T payload; +}; + +// The general implementation of Return(R). Specializations follow below. +template +class ReturnAction final { + public: + explicit ReturnAction(R value) : value_(std::move(value)) {} + + template >, // + negation>, // + std::is_convertible, // + std::is_move_constructible>::value>::type> + operator OnceAction() && { // NOLINT + return Impl(std::move(value_)); + } + + template >, // + negation>, // + std::is_convertible, // + std::is_copy_constructible>::value>::type> + operator Action() const { // NOLINT + return Impl(value_); + } + + private: + // Implements the Return(x) action for a mock function that returns type U. + template + class Impl final { + public: + // The constructor used when the return value is allowed to move from the + // input value (i.e. we are converting to OnceAction). + explicit Impl(R&& input_value) + : state_(new State(std::move(input_value))) {} + + // The constructor used when the return value is not allowed to move from + // the input value (i.e. we are converting to Action). + explicit Impl(const R& input_value) : state_(new State(input_value)) {} + + U operator()() && { return std::move(state_->value); } + U operator()() const& { return state_->value; } + + private: + // We put our state on the heap so that the compiler-generated copy/move + // constructors work correctly even when U is a reference-like type. This is + // necessary only because we eagerly create State::value (see the note on + // that symbol for details). If we instead had only the input value as a + // member then the default constructors would work fine. + // + // For example, when R is std::string and U is std::string_view, value is a + // reference to the string backed by input_value. The copy constructor would + // copy both, so that we wind up with a new input_value object (with the + // same contents) and a reference to the *old* input_value object rather + // than the new one. + struct State { + explicit State(const R& input_value_in) + : input_value(input_value_in), + // Make an implicit conversion to Result before initializing the U + // object we store, avoiding calling any explicit constructor of U + // from R. + // + // This simulates the language rules: a function with return type U + // that does `return R()` requires R to be implicitly convertible to + // U, and uses that path for the conversion, even U Result has an + // explicit constructor from R. + value(ImplicitCast_(internal::as_const(input_value))) {} + + // As above, but for the case where we're moving from the ReturnAction + // object because it's being used as a OnceAction. + explicit State(R&& input_value_in) + : input_value(std::move(input_value_in)), + // For the same reason as above we make an implicit conversion to U + // before initializing the value. + // + // Unlike above we provide the input value as an rvalue to the + // implicit conversion because this is a OnceAction: it's fine if it + // wants to consume the input value. + value(ImplicitCast_(std::move(input_value))) {} + + // A copy of the value originally provided by the user. We retain this in + // addition to the value of the mock function's result type below in case + // the latter is a reference-like type. See the std::string_view example + // in the documentation on Return. + R input_value; + + // The value we actually return, as the type returned by the mock function + // itself. + // + // We eagerly initialize this here, rather than lazily doing the implicit + // conversion automatically each time Perform is called, for historical + // reasons: in 2009-11, commit a070cbd91c (Google changelist 13540126) + // made the Action conversion operator eagerly convert the R value to + // U, but without keeping the R alive. This broke the use case discussed + // in the documentation for Return, making reference-like types such as + // std::string_view not safe to use as U where the input type R is a + // value-like type such as std::string. + // + // The example the commit gave was not very clear, nor was the issue + // thread (https://github.com/google/googlemock/issues/86), but it seems + // the worry was about reference-like input types R that flatten to a + // value-like type U when being implicitly converted. An example of this + // is std::vector::reference, which is often a proxy type with an + // reference to the underlying vector: + // + // // Helper method: have the mock function return bools according + // // to the supplied script. + // void SetActions(MockFunction& mock, + // const std::vector& script) { + // for (size_t i = 0; i < script.size(); ++i) { + // EXPECT_CALL(mock, Call(i)).WillOnce(Return(script[i])); + // } + // } + // + // TEST(Foo, Bar) { + // // Set actions using a temporary vector, whose operator[] + // // returns proxy objects that references that will be + // // dangling once the call to SetActions finishes and the + // // vector is destroyed. + // MockFunction mock; + // SetActions(mock, {false, true}); + // + // EXPECT_FALSE(mock.AsStdFunction()(0)); + // EXPECT_TRUE(mock.AsStdFunction()(1)); + // } + // + // This eager conversion helps with a simple case like this, but doesn't + // fully make these types work in general. For example the following still + // uses a dangling reference: + // + // TEST(Foo, Baz) { + // MockFunction()> mock; + // + // // Return the same vector twice, and then the empty vector + // // thereafter. + // auto action = Return(std::initializer_list{ + // "taco", "burrito", + // }); + // + // EXPECT_CALL(mock, Call) + // .WillOnce(action) + // .WillOnce(action) + // .WillRepeatedly(Return(std::vector{})); + // + // EXPECT_THAT(mock.AsStdFunction()(), + // ElementsAre("taco", "burrito")); + // EXPECT_THAT(mock.AsStdFunction()(), + // ElementsAre("taco", "burrito")); + // EXPECT_THAT(mock.AsStdFunction()(), IsEmpty()); + // } + // + U value; + }; + + const std::shared_ptr state_; + }; + + R value_; +}; + +// A specialization of ReturnAction when R is ByMoveWrapper for some T. +// +// This version applies the type system-defeating hack of moving from T even in +// the const call operator, checking at runtime that it isn't called more than +// once, since the user has declared their intent to do so by using ByMove. +template +class ReturnAction> final { + public: + explicit ReturnAction(ByMoveWrapper wrapper) + : state_(new State(std::move(wrapper.payload))) {} + + T operator()() const { + GTEST_CHECK_(!state_->called) + << "A ByMove() action must be performed at most once."; + + state_->called = true; + return std::move(state_->value); + } + + private: + // We store our state on the heap so that we are copyable as required by + // Action, despite the fact that we are stateful and T may not be copyable. + struct State { + explicit State(T&& value_in) : value(std::move(value_in)) {} + + T value; + bool called = false; + }; + + const std::shared_ptr state_; +}; + +// Implements the ReturnNull() action. +class ReturnNullAction { + public: + // Allows ReturnNull() to be used in any pointer-returning function. In C++11 + // this is enforced by returning nullptr, and in non-C++11 by asserting a + // pointer type on compile time. + template + static Result Perform(const ArgumentTuple&) { + return nullptr; + } +}; + +// Implements the Return() action. +class ReturnVoidAction { + public: + // Allows Return() to be used in any void-returning function. + template + static void Perform(const ArgumentTuple&) { + static_assert(std::is_void::value, "Result should be void."); + } +}; + +// Implements the polymorphic ReturnRef(x) action, which can be used +// in any function that returns a reference to the type of x, +// regardless of the argument types. +template +class ReturnRefAction { + public: + // Constructs a ReturnRefAction object from the reference to be returned. + explicit ReturnRefAction(T& ref) : ref_(ref) {} // NOLINT + + // This template type conversion operator allows ReturnRef(x) to be + // used in ANY function that returns a reference to x's type. + template + operator Action() const { + typedef typename Function::Result Result; + // Asserts that the function return type is a reference. This + // catches the user error of using ReturnRef(x) when Return(x) + // should be used, and generates some helpful error message. + static_assert(std::is_reference::value, + "use Return instead of ReturnRef to return a value"); + return Action(new Impl(ref_)); + } + + private: + // Implements the ReturnRef(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(T& ref) : ref_(ref) {} // NOLINT + + Result Perform(const ArgumentTuple&) override { return ref_; } + + private: + T& ref_; + }; + + T& ref_; +}; + +// Implements the polymorphic ReturnRefOfCopy(x) action, which can be +// used in any function that returns a reference to the type of x, +// regardless of the argument types. +template +class ReturnRefOfCopyAction { + public: + // Constructs a ReturnRefOfCopyAction object from the reference to + // be returned. + explicit ReturnRefOfCopyAction(const T& value) : value_(value) {} // NOLINT + + // This template type conversion operator allows ReturnRefOfCopy(x) to be + // used in ANY function that returns a reference to x's type. + template + operator Action() const { + typedef typename Function::Result Result; + // Asserts that the function return type is a reference. This + // catches the user error of using ReturnRefOfCopy(x) when Return(x) + // should be used, and generates some helpful error message. + static_assert(std::is_reference::value, + "use Return instead of ReturnRefOfCopy to return a value"); + return Action(new Impl(value_)); + } + + private: + // Implements the ReturnRefOfCopy(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const T& value) : value_(value) {} // NOLINT + + Result Perform(const ArgumentTuple&) override { return value_; } + + private: + T value_; + }; + + const T value_; +}; + +// Implements the polymorphic ReturnRoundRobin(v) action, which can be +// used in any function that returns the element_type of v. +template +class ReturnRoundRobinAction { + public: + explicit ReturnRoundRobinAction(std::vector values) { + GTEST_CHECK_(!values.empty()) + << "ReturnRoundRobin requires at least one element."; + state_->values = std::move(values); + } + + template + T operator()(Args&&...) const { + return state_->Next(); + } + + private: + struct State { + T Next() { + T ret_val = values[i++]; + if (i == values.size()) i = 0; + return ret_val; + } + + std::vector values; + size_t i = 0; + }; + std::shared_ptr state_ = std::make_shared(); +}; + +// Implements the polymorphic DoDefault() action. +class DoDefaultAction { + public: + // This template type conversion operator allows DoDefault() to be + // used in any function. + template + operator Action() const { + return Action(); + } // NOLINT +}; + +// Implements the Assign action to set a given pointer referent to a +// particular value. +template +class AssignAction { + public: + AssignAction(T1* ptr, T2 value) : ptr_(ptr), value_(value) {} + + template + void Perform(const ArgumentTuple& /* args */) const { + *ptr_ = value_; + } + + private: + T1* const ptr_; + const T2 value_; +}; + +#ifndef GTEST_OS_WINDOWS_MOBILE + +// Implements the SetErrnoAndReturn action to simulate return from +// various system calls and libc functions. +template +class SetErrnoAndReturnAction { + public: + SetErrnoAndReturnAction(int errno_value, T result) + : errno_(errno_value), result_(result) {} + template + Result Perform(const ArgumentTuple& /* args */) const { + errno = errno_; + return result_; + } + + private: + const int errno_; + const T result_; +}; + +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Implements the SetArgumentPointee(x) action for any function +// whose N-th argument (0-based) is a pointer to x's type. +template +struct SetArgumentPointeeAction { + A value; + + template + void operator()(const Args&... args) const { + *::std::get(std::tie(args...)) = value; + } +}; + +// Implements the Invoke(object_ptr, &Class::Method) action. +template +struct InvokeMethodAction { + Class* const obj_ptr; + const MethodPtr method_ptr; + + template + auto operator()(Args&&... args) const + -> decltype((obj_ptr->*method_ptr)(std::forward(args)...)) { + return (obj_ptr->*method_ptr)(std::forward(args)...); + } +}; + +// Implements the InvokeWithoutArgs(f) action. The template argument +// FunctionImpl is the implementation type of f, which can be either a +// function pointer or a functor. InvokeWithoutArgs(f) can be used as an +// Action as long as f's type is compatible with F. +template +struct InvokeWithoutArgsAction { + FunctionImpl function_impl; + + // Allows InvokeWithoutArgs(f) to be used as any action whose type is + // compatible with f. + template + auto operator()(const Args&...) -> decltype(function_impl()) { + return function_impl(); + } +}; + +// Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action. +template +struct InvokeMethodWithoutArgsAction { + Class* const obj_ptr; + const MethodPtr method_ptr; + + using ReturnType = + decltype((std::declval()->*std::declval())()); + + template + ReturnType operator()(const Args&...) const { + return (obj_ptr->*method_ptr)(); + } +}; + +// Implements the IgnoreResult(action) action. +template +class IgnoreResultAction { + public: + explicit IgnoreResultAction(const A& action) : action_(action) {} + + template + operator Action() const { + // Assert statement belongs here because this is the best place to verify + // conditions on F. It produces the clearest error messages + // in most compilers. + // Impl really belongs in this scope as a local class but can't + // because MSVC produces duplicate symbols in different translation units + // in this case. Until MS fixes that bug we put Impl into the class scope + // and put the typedef both here (for use in assert statement) and + // in the Impl class. But both definitions must be the same. + typedef typename internal::Function::Result Result; + + // Asserts at compile time that F returns void. + static_assert(std::is_void::value, "Result type should be void."); + + return Action(new Impl(action_)); + } + + private: + template + class Impl : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const A& action) : action_(action) {} + + void Perform(const ArgumentTuple& args) override { + // Performs the action and ignores its result. + action_.Perform(args); + } + + private: + // Type OriginalFunction is the same as F except that its return + // type is IgnoredValue. + typedef + typename internal::Function::MakeResultIgnoredValue OriginalFunction; + + const Action action_; + }; + + const A action_; +}; + +template +struct WithArgsAction { + InnerAction inner_action; + + // The signature of the function as seen by the inner action, given an out + // action with the given result and argument types. + template + using InnerSignature = + R(typename std::tuple_element>::type...); + + // Rather than a call operator, we must define conversion operators to + // particular action types. This is necessary for embedded actions like + // DoDefault(), which rely on an action conversion operators rather than + // providing a call operator because even with a particular set of arguments + // they don't have a fixed return type. + + template < + typename R, typename... Args, + typename std::enable_if< + std::is_convertible>...)>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + struct OA { + OnceAction> inner_action; + + R operator()(Args&&... args) && { + return std::move(inner_action) + .Call(std::get( + std::forward_as_tuple(std::forward(args)...))...); + } + }; + + return OA{std::move(inner_action)}; + } + + template < + typename R, typename... Args, + typename std::enable_if< + std::is_convertible>...)>>::value, + int>::type = 0> + operator Action() const { // NOLINT + Action> converted(inner_action); + + return [converted](Args&&... args) -> R { + return converted.Perform(std::forward_as_tuple( + std::get(std::forward_as_tuple(std::forward(args)...))...)); + }; + } +}; + +template +class DoAllAction; + +// Base case: only a single action. +template +class DoAllAction { + public: + struct UserConstructorTag {}; + + template + explicit DoAllAction(UserConstructorTag, T&& action) + : final_action_(std::forward(action)) {} + + // Rather than a call operator, we must define conversion operators to + // particular action types. This is necessary for embedded actions like + // DoDefault(), which rely on an action conversion operators rather than + // providing a call operator because even with a particular set of arguments + // they don't have a fixed return type. + + // We support conversion to OnceAction whenever the sub-action does. + template >::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + return std::move(final_action_); + } + + // We also support conversion to OnceAction whenever the sub-action supports + // conversion to Action (since any Action can also be a OnceAction). + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + negation< + std::is_convertible>>, + std::is_convertible>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + return Action(std::move(final_action_)); + } + + // We support conversion to Action whenever the sub-action does. + template < + typename R, typename... Args, + typename std::enable_if< + std::is_convertible>::value, + int>::type = 0> + operator Action() const { // NOLINT + return final_action_; + } + + private: + FinalAction final_action_; +}; + +// Recursive case: support N actions by calling the initial action and then +// calling through to the base class containing N-1 actions. +template +class DoAllAction + : private DoAllAction { + private: + using Base = DoAllAction; + + // The type of reference that should be provided to an initial action for a + // mocked function parameter of type T. + // + // There are two quirks here: + // + // * Unlike most forwarding functions, we pass scalars through by value. + // This isn't strictly necessary because an lvalue reference would work + // fine too and be consistent with other non-reference types, but it's + // perhaps less surprising. + // + // For example if the mocked function has signature void(int), then it + // might seem surprising for the user's initial action to need to be + // convertible to Action. This is perhaps less + // surprising for a non-scalar type where there may be a performance + // impact, or it might even be impossible, to pass by value. + // + // * More surprisingly, `const T&` is often not a const reference type. + // By the reference collapsing rules in C++17 [dcl.ref]/6, if T refers to + // U& or U&& for some non-scalar type U, then InitialActionArgType is + // U&. In other words, we may hand over a non-const reference. + // + // So for example, given some non-scalar type Obj we have the following + // mappings: + // + // T InitialActionArgType + // ------- ----------------------- + // Obj const Obj& + // Obj& Obj& + // Obj&& Obj& + // const Obj const Obj& + // const Obj& const Obj& + // const Obj&& const Obj& + // + // In other words, the initial actions get a mutable view of an non-scalar + // argument if and only if the mock function itself accepts a non-const + // reference type. They are never given an rvalue reference to an + // non-scalar type. + // + // This situation makes sense if you imagine use with a matcher that is + // designed to write through a reference. For example, if the caller wants + // to fill in a reference argument and then return a canned value: + // + // EXPECT_CALL(mock, Call) + // .WillOnce(DoAll(SetArgReferee<0>(17), Return(19))); + // + template + using InitialActionArgType = + typename std::conditional::value, T, const T&>::type; + + public: + struct UserConstructorTag {}; + + template + explicit DoAllAction(UserConstructorTag, T&& initial_action, + U&&... other_actions) + : Base({}, std::forward(other_actions)...), + initial_action_(std::forward(initial_action)) {} + + // We support conversion to OnceAction whenever both the initial action and + // the rest support conversion to OnceAction. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction...)>>, + std::is_convertible>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + // Return an action that first calls the initial action with arguments + // filtered through InitialActionArgType, then forwards arguments directly + // to the base class to deal with the remaining actions. + struct OA { + OnceAction...)> initial_action; + OnceAction remaining_actions; + + R operator()(Args... args) && { + std::move(initial_action) + .Call(static_cast>(args)...); + + return std::move(remaining_actions).Call(std::forward(args)...); + } + }; + + return OA{ + std::move(initial_action_), + std::move(static_cast(*this)), + }; + } + + // We also support conversion to OnceAction whenever the initial action + // supports conversion to Action (since any Action can also be a OnceAction). + // + // The remaining sub-actions must also be compatible, but we don't need to + // special case them because the base class deals with them. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + negation...)>>>, + std::is_convertible...)>>, + std::is_convertible>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + return DoAll( + Action...)>(std::move(initial_action_)), + std::move(static_cast(*this))); + } + + // We support conversion to Action whenever both the initial action and the + // rest support conversion to Action. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + std::is_convertible...)>>, + std::is_convertible>>::value, + int>::type = 0> + operator Action() const { // NOLINT + // Return an action that first calls the initial action with arguments + // filtered through InitialActionArgType, then forwards arguments directly + // to the base class to deal with the remaining actions. + struct OA { + Action...)> initial_action; + Action remaining_actions; + + R operator()(Args... args) const { + initial_action.Perform(std::forward_as_tuple( + static_cast>(args)...)); + + return remaining_actions.Perform( + std::forward_as_tuple(std::forward(args)...)); + } + }; + + return OA{ + initial_action_, + static_cast(*this), + }; + } + + private: + InitialAction initial_action_; +}; + +template +struct ReturnNewAction { + T* operator()() const { + return internal::Apply( + [](const Params&... unpacked_params) { + return new T(unpacked_params...); + }, + params); + } + std::tuple params; +}; + +template +struct ReturnArgAction { + template ::type> + auto operator()(Args&&... args) const + -> decltype(std::get( + std::forward_as_tuple(std::forward(args)...))) { + return std::get(std::forward_as_tuple(std::forward(args)...)); + } +}; + +template +struct SaveArgAction { + Ptr pointer; + + template + void operator()(const Args&... args) const { + *pointer = std::get(std::tie(args...)); + } +}; + +template +struct SaveArgPointeeAction { + Ptr pointer; + + template + void operator()(const Args&... args) const { + *pointer = *std::get(std::tie(args...)); + } +}; + +template +struct SetArgRefereeAction { + T value; + + template + void operator()(Args&&... args) const { + using argk_type = + typename ::std::tuple_element>::type; + static_assert(std::is_lvalue_reference::value, + "Argument must be a reference type."); + std::get(std::tie(args...)) = value; + } +}; + +template +struct SetArrayArgumentAction { + I1 first; + I2 last; + + template + void operator()(const Args&... args) const { + auto value = std::get(std::tie(args...)); + for (auto it = first; it != last; ++it, (void)++value) { + *value = *it; + } + } +}; + +template +struct DeleteArgAction { + template + void operator()(const Args&... args) const { + delete std::get(std::tie(args...)); + } +}; + +template +struct ReturnPointeeAction { + Ptr pointer; + template + auto operator()(const Args&...) const -> decltype(*pointer) { + return *pointer; + } +}; + +#if GTEST_HAS_EXCEPTIONS +template +struct ThrowAction { + T exception; + // We use a conversion operator to adapt to any return type. + template + operator Action() const { // NOLINT + T copy = exception; + return [copy](Args...) -> R { throw copy; }; + } +}; +struct RethrowAction { + std::exception_ptr exception; + template + operator Action() const { // NOLINT + return [ex = exception](Args...) -> R { std::rethrow_exception(ex); }; + } +}; +#endif // GTEST_HAS_EXCEPTIONS + +} // namespace internal + +// An Unused object can be implicitly constructed from ANY value. +// This is handy when defining actions that ignore some or all of the +// mock function arguments. For example, given +// +// MOCK_METHOD3(Foo, double(const string& label, double x, double y)); +// MOCK_METHOD3(Bar, double(int index, double x, double y)); +// +// instead of +// +// double DistanceToOriginWithLabel(const string& label, double x, double y) { +// return sqrt(x*x + y*y); +// } +// double DistanceToOriginWithIndex(int index, double x, double y) { +// return sqrt(x*x + y*y); +// } +// ... +// EXPECT_CALL(mock, Foo("abc", _, _)) +// .WillOnce(Invoke(DistanceToOriginWithLabel)); +// EXPECT_CALL(mock, Bar(5, _, _)) +// .WillOnce(Invoke(DistanceToOriginWithIndex)); +// +// you could write +// +// // We can declare any uninteresting argument as Unused. +// double DistanceToOrigin(Unused, double x, double y) { +// return sqrt(x*x + y*y); +// } +// ... +// EXPECT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin)); +// EXPECT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin)); +typedef internal::IgnoredValue Unused; + +// Creates an action that does actions a1, a2, ..., sequentially in +// each invocation. All but the last action will have a readonly view of the +// arguments. +template +internal::DoAllAction::type...> DoAll( + Action&&... action) { + return internal::DoAllAction::type...>( + {}, std::forward(action)...); +} + +// WithArg(an_action) creates an action that passes the k-th +// (0-based) argument of the mock function to an_action and performs +// it. It adapts an action accepting one argument to one that accepts +// multiple arguments. For convenience, we also provide +// WithArgs(an_action) (defined below) as a synonym. +template +internal::WithArgsAction::type, k> WithArg( + InnerAction&& action) { + return {std::forward(action)}; +} + +// WithArgs(an_action) creates an action that passes +// the selected arguments of the mock function to an_action and +// performs it. It serves as an adaptor between actions with +// different argument lists. +template +internal::WithArgsAction::type, k, ks...> +WithArgs(InnerAction&& action) { + return {std::forward(action)}; +} + +// WithoutArgs(inner_action) can be used in a mock function with a +// non-empty argument list to perform inner_action, which takes no +// argument. In other words, it adapts an action accepting no +// argument to one that accepts (and ignores) arguments. +template +internal::WithArgsAction::type> WithoutArgs( + InnerAction&& action) { + return {std::forward(action)}; +} + +// Creates an action that returns a value. +// +// The returned type can be used with a mock function returning a non-void, +// non-reference type U as follows: +// +// * If R is convertible to U and U is move-constructible, then the action can +// be used with WillOnce. +// +// * If const R& is convertible to U and U is copy-constructible, then the +// action can be used with both WillOnce and WillRepeatedly. +// +// The mock expectation contains the R value from which the U return value is +// constructed (a move/copy of the argument to Return). This means that the R +// value will survive at least until the mock object's expectations are cleared +// or the mock object is destroyed, meaning that U can safely be a +// reference-like type such as std::string_view: +// +// // The mock function returns a view of a copy of the string fed to +// // Return. The view is valid even after the action is performed. +// MockFunction mock; +// EXPECT_CALL(mock, Call).WillOnce(Return(std::string("taco"))); +// const std::string_view result = mock.AsStdFunction()(); +// EXPECT_EQ("taco", result); +// +template +internal::ReturnAction Return(R value) { + return internal::ReturnAction(std::move(value)); +} + +// Creates an action that returns NULL. +inline PolymorphicAction ReturnNull() { + return MakePolymorphicAction(internal::ReturnNullAction()); +} + +// Creates an action that returns from a void function. +inline PolymorphicAction Return() { + return MakePolymorphicAction(internal::ReturnVoidAction()); +} + +// Creates an action that returns the reference to a variable. +template +inline internal::ReturnRefAction ReturnRef(R& x) { // NOLINT + return internal::ReturnRefAction(x); +} + +// Prevent using ReturnRef on reference to temporary. +template +internal::ReturnRefAction ReturnRef(R&&) = delete; + +// Creates an action that returns the reference to a copy of the +// argument. The copy is created when the action is constructed and +// lives as long as the action. +template +inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { + return internal::ReturnRefOfCopyAction(x); +} + +// DEPRECATED: use Return(x) directly with WillOnce. +// +// Modifies the parent action (a Return() action) to perform a move of the +// argument instead of a copy. +// Return(ByMove()) actions can only be executed once and will assert this +// invariant. +template +internal::ByMoveWrapper ByMove(R x) { + return internal::ByMoveWrapper(std::move(x)); +} + +// Creates an action that returns an element of `vals`. Calling this action will +// repeatedly return the next value from `vals` until it reaches the end and +// will restart from the beginning. +template +internal::ReturnRoundRobinAction ReturnRoundRobin(std::vector vals) { + return internal::ReturnRoundRobinAction(std::move(vals)); +} + +// Creates an action that returns an element of `vals`. Calling this action will +// repeatedly return the next value from `vals` until it reaches the end and +// will restart from the beginning. +template +internal::ReturnRoundRobinAction ReturnRoundRobin( + std::initializer_list vals) { + return internal::ReturnRoundRobinAction(std::vector(vals)); +} + +// Creates an action that does the default action for the give mock function. +inline internal::DoDefaultAction DoDefault() { + return internal::DoDefaultAction(); +} + +// Creates an action that sets the variable pointed by the N-th +// (0-based) function argument to 'value'. +template +internal::SetArgumentPointeeAction SetArgPointee(T value) { + return {std::move(value)}; +} + +// The following version is DEPRECATED. +template +internal::SetArgumentPointeeAction SetArgumentPointee(T value) { + return {std::move(value)}; +} + +// Creates an action that sets a pointer referent to a given value. +template +PolymorphicAction> Assign(T1* ptr, T2 val) { + return MakePolymorphicAction(internal::AssignAction(ptr, val)); +} + +#ifndef GTEST_OS_WINDOWS_MOBILE + +// Creates an action that sets errno and returns the appropriate error. +template +PolymorphicAction> SetErrnoAndReturn( + int errval, T result) { + return MakePolymorphicAction( + internal::SetErrnoAndReturnAction(errval, result)); +} + +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Various overloads for Invoke(). + +// Legacy function. +// Actions can now be implicitly constructed from callables. No need to create +// wrapper objects. +// This function exists for backwards compatibility. +template +typename std::decay::type Invoke(FunctionImpl&& function_impl) { + return std::forward(function_impl); +} + +// Creates an action that invokes the given method on the given object +// with the mock function's arguments. +template +internal::InvokeMethodAction Invoke(Class* obj_ptr, + MethodPtr method_ptr) { + return {obj_ptr, method_ptr}; +} + +// Creates an action that invokes 'function_impl' with no argument. +template +internal::InvokeWithoutArgsAction::type> +InvokeWithoutArgs(FunctionImpl function_impl) { + return {std::move(function_impl)}; +} + +// Creates an action that invokes the given method on the given object +// with no argument. +template +internal::InvokeMethodWithoutArgsAction InvokeWithoutArgs( + Class* obj_ptr, MethodPtr method_ptr) { + return {obj_ptr, method_ptr}; +} + +// Creates an action that performs an_action and throws away its +// result. In other words, it changes the return type of an_action to +// void. an_action MUST NOT return void, or the code won't compile. +template +inline internal::IgnoreResultAction IgnoreResult(const A& an_action) { + return internal::IgnoreResultAction(an_action); +} + +// Creates a reference wrapper for the given L-value. If necessary, +// you can explicitly specify the type of the reference. For example, +// suppose 'derived' is an object of type Derived, ByRef(derived) +// would wrap a Derived&. If you want to wrap a const Base& instead, +// where Base is a base class of Derived, just write: +// +// ByRef(derived) +// +// N.B. ByRef is redundant with std::ref, std::cref and std::reference_wrapper. +// However, it may still be used for consistency with ByMove(). +template +inline ::std::reference_wrapper ByRef(T& l_value) { // NOLINT + return ::std::reference_wrapper(l_value); +} + +// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new +// instance of type T, constructed on the heap with constructor arguments +// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. +template +internal::ReturnNewAction::type...> ReturnNew( + Params&&... params) { + return {std::forward_as_tuple(std::forward(params)...)}; +} + +// Action ReturnArg() returns the k-th argument of the mock function. +template +internal::ReturnArgAction ReturnArg() { + return {}; +} + +// Action SaveArg(pointer) saves the k-th (0-based) argument of the +// mock function to *pointer. +template +internal::SaveArgAction SaveArg(Ptr pointer) { + return {pointer}; +} + +// Action SaveArgPointee(pointer) saves the value pointed to +// by the k-th (0-based) argument of the mock function to *pointer. +template +internal::SaveArgPointeeAction SaveArgPointee(Ptr pointer) { + return {pointer}; +} + +// Action SetArgReferee(value) assigns 'value' to the variable +// referenced by the k-th (0-based) argument of the mock function. +template +internal::SetArgRefereeAction::type> SetArgReferee( + T&& value) { + return {std::forward(value)}; +} + +// Action SetArrayArgument(first, last) copies the elements in +// source range [first, last) to the array pointed to by the k-th +// (0-based) argument, which can be either a pointer or an +// iterator. The action does not take ownership of the elements in the +// source range. +template +internal::SetArrayArgumentAction SetArrayArgument(I1 first, + I2 last) { + return {first, last}; +} + +// Action DeleteArg() deletes the k-th (0-based) argument of the mock +// function. +template +internal::DeleteArgAction DeleteArg() { + return {}; +} + +// This action returns the value pointed to by 'pointer'. +template +internal::ReturnPointeeAction ReturnPointee(Ptr pointer) { + return {pointer}; +} + +#if GTEST_HAS_EXCEPTIONS +// Action Throw(exception) can be used in a mock function of any type +// to throw the given exception. Any copyable value can be thrown, +// except for std::exception_ptr, which is likely a mistake if +// thrown directly. +template +typename std::enable_if< + !std::is_base_of::type>::value, + internal::ThrowAction::type>>::type +Throw(T&& exception) { + return {std::forward(exception)}; +} +// Action Rethrow(exception_ptr) can be used in a mock function of any type +// to rethrow any exception_ptr. Note that the same object is thrown each time. +inline internal::RethrowAction Rethrow(std::exception_ptr exception) { + return {std::move(exception)}; +} +#endif // GTEST_HAS_EXCEPTIONS + +namespace internal { + +// A macro from the ACTION* family (defined later in gmock-generated-actions.h) +// defines an action that can be used in a mock function. Typically, +// these actions only care about a subset of the arguments of the mock +// function. For example, if such an action only uses the second +// argument, it can be used in any mock function that takes >= 2 +// arguments where the type of the second argument is compatible. +// +// Therefore, the action implementation must be prepared to take more +// arguments than it needs. The ExcessiveArg type is used to +// represent those excessive arguments. In order to keep the compiler +// error messages tractable, we define it in the testing namespace +// instead of testing::internal. However, this is an INTERNAL TYPE +// and subject to change without notice, so a user MUST NOT USE THIS +// TYPE DIRECTLY. +struct ExcessiveArg {}; + +// Builds an implementation of an Action<> for some particular signature, using +// a class defined by an ACTION* macro. +template +struct ActionImpl; + +template +struct ImplBase { + struct Holder { + // Allows each copy of the Action<> to get to the Impl. + explicit operator const Impl&() const { return *ptr; } + std::shared_ptr ptr; + }; + using type = typename std::conditional::value, + Impl, Holder>::type; +}; + +template +struct ActionImpl : ImplBase::type { + using Base = typename ImplBase::type; + using function_type = R(Args...); + using args_type = std::tuple; + + ActionImpl() = default; // Only defined if appropriate for Base. + explicit ActionImpl(std::shared_ptr impl) : Base{std::move(impl)} {} + + R operator()(Args&&... arg) const { + static constexpr size_t kMaxArgs = + sizeof...(Args) <= 10 ? sizeof...(Args) : 10; + return Apply(std::make_index_sequence{}, + std::make_index_sequence<10 - kMaxArgs>{}, + args_type{std::forward(arg)...}); + } + + template + R Apply(std::index_sequence, std::index_sequence, + const args_type& args) const { + // Impl need not be specific to the signature of action being implemented; + // only the implementing function body needs to have all of the specific + // types instantiated. Up to 10 of the args that are provided by the + // args_type get passed, followed by a dummy of unspecified type for the + // remainder up to 10 explicit args. + static constexpr ExcessiveArg kExcessArg{}; + return static_cast(*this) + .template gmock_PerformImpl< + /*function_type=*/function_type, /*return_type=*/R, + /*args_type=*/args_type, + /*argN_type=*/ + typename std::tuple_element::type...>( + /*args=*/args, std::get(args)..., + ((void)excess_id, kExcessArg)...); + } +}; + +// Stores a default-constructed Impl as part of the Action<>'s +// std::function<>. The Impl should be trivial to copy. +template +::testing::Action MakeAction() { + return ::testing::Action(ActionImpl()); +} + +// Stores just the one given instance of Impl. +template +::testing::Action MakeAction(std::shared_ptr impl) { + return ::testing::Action(ActionImpl(std::move(impl))); +} + +#define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \ + , GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED const arg##i##_type& arg##i +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \ + GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED const args_type& args GMOCK_PP_REPEAT( \ + GMOCK_INTERNAL_ARG_UNUSED, , 10) + +#define GMOCK_INTERNAL_ARG(i, data, el) , const arg##i##_type& arg##i +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_ \ + const args_type& args GMOCK_PP_REPEAT(GMOCK_INTERNAL_ARG, , 10) + +#define GMOCK_INTERNAL_TEMPLATE_ARG(i, data, el) , typename arg##i##_type +#define GMOCK_ACTION_TEMPLATE_ARGS_NAMES_ \ + GMOCK_PP_TAIL(GMOCK_PP_REPEAT(GMOCK_INTERNAL_TEMPLATE_ARG, , 10)) + +#define GMOCK_INTERNAL_TYPENAME_PARAM(i, data, param) , typename param##_type +#define GMOCK_ACTION_TYPENAME_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPENAME_PARAM, , params)) + +#define GMOCK_INTERNAL_TYPE_PARAM(i, data, param) , param##_type +#define GMOCK_ACTION_TYPE_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_PARAM, , params)) + +#define GMOCK_INTERNAL_TYPE_GVALUE_PARAM(i, data, param) \ + , param##_type gmock_p##i +#define GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_GVALUE_PARAM, , params)) + +#define GMOCK_INTERNAL_GVALUE_PARAM(i, data, param) \ + , std::forward(gmock_p##i) +#define GMOCK_ACTION_GVALUE_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GVALUE_PARAM, , params)) + +#define GMOCK_INTERNAL_INIT_PARAM(i, data, param) \ + , param(::std::forward(gmock_p##i)) +#define GMOCK_ACTION_INIT_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_INIT_PARAM, , params)) + +#define GMOCK_INTERNAL_FIELD_PARAM(i, data, param) param##_type param; +#define GMOCK_ACTION_FIELD_PARAMS_(params) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_FIELD_PARAM, , params) + +#define GMOCK_INTERNAL_ACTION(name, full_name, params) \ + template \ + class full_name { \ + public: \ + explicit full_name(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ + : impl_(std::make_shared( \ + GMOCK_ACTION_GVALUE_PARAMS_(params))) {} \ + full_name(const full_name&) = default; \ + full_name(full_name&&) noexcept = default; \ + template \ + operator ::testing::Action() const { \ + return ::testing::internal::MakeAction(impl_); \ + } \ + \ + private: \ + class gmock_Impl { \ + public: \ + explicit gmock_Impl(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ + : GMOCK_ACTION_INIT_PARAMS_(params) {} \ + template \ + return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ + GMOCK_ACTION_FIELD_PARAMS_(params) \ + }; \ + std::shared_ptr impl_; \ + }; \ + template \ + inline full_name name( \ + GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) GTEST_MUST_USE_RESULT_; \ + template \ + inline full_name name( \ + GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) { \ + return full_name( \ + GMOCK_ACTION_GVALUE_PARAMS_(params)); \ + } \ + template \ + template \ + return_type \ + full_name::gmock_Impl::gmock_PerformImpl( \ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +} // namespace internal + +// Similar to GMOCK_INTERNAL_ACTION, but no bound parameters are stored. +#define ACTION(name) \ + class name##Action { \ + public: \ + explicit name##Action() noexcept {} \ + name##Action(const name##Action&) noexcept {} \ + template \ + operator ::testing::Action() const { \ + return ::testing::internal::MakeAction(); \ + } \ + \ + private: \ + class gmock_Impl { \ + public: \ + template \ + return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ + }; \ + }; \ + inline name##Action name() GTEST_MUST_USE_RESULT_; \ + inline name##Action name() { return name##Action(); } \ + template \ + return_type name##Action::gmock_Impl::gmock_PerformImpl( \ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP, (__VA_ARGS__)) + +#define ACTION_P2(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP2, (__VA_ARGS__)) + +#define ACTION_P3(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP3, (__VA_ARGS__)) + +#define ACTION_P4(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP4, (__VA_ARGS__)) + +#define ACTION_P5(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP5, (__VA_ARGS__)) + +#define ACTION_P6(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP6, (__VA_ARGS__)) + +#define ACTION_P7(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP7, (__VA_ARGS__)) + +#define ACTION_P8(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP8, (__VA_ARGS__)) + +#define ACTION_P9(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP9, (__VA_ARGS__)) + +#define ACTION_P10(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP10, (__VA_ARGS__)) + +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4100 + +#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ diff --git a/GTest/include/gmock/gmock-cardinalities.h b/GTest/include/gmock/gmock-cardinalities.h new file mode 100644 index 0000000..533e604 --- /dev/null +++ b/GTest/include/gmock/gmock-cardinalities.h @@ -0,0 +1,159 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used cardinalities. More +// cardinalities can be defined by the user implementing the +// CardinalityInterface interface if necessary. + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ + +#include + +#include +#include // NOLINT + +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// To implement a cardinality Foo, define: +// 1. a class FooCardinality that implements the +// CardinalityInterface interface, and +// 2. a factory function that creates a Cardinality object from a +// const FooCardinality*. +// +// The two-level delegation design follows that of Matcher, providing +// consistency for extension developers. It also eases ownership +// management as Cardinality objects can now be copied like plain values. + +// The implementation of a cardinality. +class CardinalityInterface { + public: + virtual ~CardinalityInterface() = default; + + // Conservative estimate on the lower/upper bound of the number of + // calls allowed. + virtual int ConservativeLowerBound() const { return 0; } + virtual int ConservativeUpperBound() const { return INT_MAX; } + + // Returns true if and only if call_count calls will satisfy this + // cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const = 0; + + // Returns true if and only if call_count calls will saturate this + // cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const = 0; + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; +}; + +// A Cardinality is a copyable and IMMUTABLE (except by assignment) +// object that specifies how many times a mock function is expected to +// be called. The implementation of Cardinality is just a std::shared_ptr +// to const CardinalityInterface. Don't inherit from Cardinality! +class GTEST_API_ Cardinality { + public: + // Constructs a null cardinality. Needed for storing Cardinality + // objects in STL containers. + Cardinality() = default; + + // Constructs a Cardinality from its implementation. + explicit Cardinality(const CardinalityInterface* impl) : impl_(impl) {} + + // Conservative estimate on the lower/upper bound of the number of + // calls allowed. + int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); } + int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); } + + // Returns true if and only if call_count calls will satisfy this + // cardinality. + bool IsSatisfiedByCallCount(int call_count) const { + return impl_->IsSatisfiedByCallCount(call_count); + } + + // Returns true if and only if call_count calls will saturate this + // cardinality. + bool IsSaturatedByCallCount(int call_count) const { + return impl_->IsSaturatedByCallCount(call_count); + } + + // Returns true if and only if call_count calls will over-saturate this + // cardinality, i.e. exceed the maximum number of allowed calls. + bool IsOverSaturatedByCallCount(int call_count) const { + return impl_->IsSaturatedByCallCount(call_count) && + !impl_->IsSatisfiedByCallCount(call_count); + } + + // Describes self to an ostream + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the given actual call count to an ostream. + static void DescribeActualCallCountTo(int actual_call_count, + ::std::ostream* os); + + private: + std::shared_ptr impl_; +}; + +// Creates a cardinality that allows at least n calls. +GTEST_API_ Cardinality AtLeast(int n); + +// Creates a cardinality that allows at most n calls. +GTEST_API_ Cardinality AtMost(int n); + +// Creates a cardinality that allows any number of calls. +GTEST_API_ Cardinality AnyNumber(); + +// Creates a cardinality that allows between min and max calls. +GTEST_API_ Cardinality Between(int min, int max); + +// Creates a cardinality that allows exactly n calls. +GTEST_API_ Cardinality Exactly(int n); + +// Creates a cardinality from its implementation. +inline Cardinality MakeCardinality(const CardinalityInterface* c) { + return Cardinality(c); +} + +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ diff --git a/GTest/include/gmock/gmock-function-mocker.h b/GTest/include/gmock/gmock-function-mocker.h new file mode 100644 index 0000000..d2cb13c --- /dev/null +++ b/GTest/include/gmock/gmock-function-mocker.h @@ -0,0 +1,519 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements MOCK_METHOD. + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_ + +#include +#include // IWYU pragma: keep +#include // IWYU pragma: keep + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-pp.h" + +namespace testing { +namespace internal { +template +using identity_t = T; + +template +struct ThisRefAdjuster { + template + using AdjustT = typename std::conditional< + std::is_const::type>::value, + typename std::conditional::value, + const T&, const T&&>::type, + typename std::conditional::value, T&, + T&&>::type>::type; + + template + static AdjustT Adjust(const MockType& mock) { + return static_cast>(const_cast(mock)); + } +}; + +constexpr bool PrefixOf(const char* a, const char* b) { + return *a == 0 || (*a == *b && internal::PrefixOf(a + 1, b + 1)); +} + +template +constexpr bool StartsWith(const char (&prefix)[N], const char (&str)[M]) { + return N <= M && internal::PrefixOf(prefix, str); +} + +template +constexpr bool EndsWith(const char (&suffix)[N], const char (&str)[M]) { + return N <= M && internal::PrefixOf(suffix, str + M - N); +} + +template +constexpr bool Equals(const char (&a)[N], const char (&b)[M]) { + return N == M && internal::PrefixOf(a, b); +} + +template +constexpr bool ValidateSpec(const char (&spec)[N]) { + return internal::Equals("const", spec) || + internal::Equals("override", spec) || + internal::Equals("final", spec) || + internal::Equals("noexcept", spec) || + (internal::StartsWith("noexcept(", spec) && + internal::EndsWith(")", spec)) || + internal::Equals("ref(&)", spec) || + internal::Equals("ref(&&)", spec) || + (internal::StartsWith("Calltype(", spec) && + internal::EndsWith(")", spec)); +} + +} // namespace internal + +// The style guide prohibits "using" statements in a namespace scope +// inside a header file. However, the FunctionMocker class template +// is meant to be defined in the ::testing namespace. The following +// line is just a trick for working around a bug in MSVC 8.0, which +// cannot handle it if we define FunctionMocker in ::testing. +using internal::FunctionMocker; +} // namespace testing + +#define MOCK_METHOD(...) \ + GMOCK_INTERNAL_WARNING_PUSH() \ + GMOCK_INTERNAL_WARNING_CLANG(ignored, "-Wunused-member-function") \ + GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__) \ + GMOCK_INTERNAL_WARNING_POP() + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_1(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_2(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_3(_Ret, _MethodName, _Args) \ + GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, ()) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, _Spec) \ + GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Args); \ + GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Spec); \ + GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ + GMOCK_PP_NARG0 _Args, GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)); \ + GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ + GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ + GMOCK_PP_NARG0 _Args, _MethodName, GMOCK_INTERNAL_HAS_CONST(_Spec), \ + GMOCK_INTERNAL_HAS_OVERRIDE(_Spec), GMOCK_INTERNAL_HAS_FINAL(_Spec), \ + GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Spec), \ + GMOCK_INTERNAL_GET_CALLTYPE_SPEC(_Spec), \ + GMOCK_INTERNAL_GET_REF_SPEC(_Spec), \ + (GMOCK_INTERNAL_SIGNATURE(_Ret, _Args))) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_5(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_6(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_7(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_WRONG_ARITY(...) \ + static_assert( \ + false, \ + "MOCK_METHOD must be called with 3 or 4 arguments. _Ret, " \ + "_MethodName, _Args and optionally _Spec. _Args and _Spec must be " \ + "enclosed in parentheses. If _Ret is a type with unprotected commas, " \ + "it must also be enclosed in parentheses.") + +#define GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Tuple) \ + static_assert( \ + GMOCK_PP_IS_ENCLOSED_PARENS(_Tuple), \ + GMOCK_PP_STRINGIZE(_Tuple) " should be enclosed in parentheses.") + +#define GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE(_N, ...) \ + static_assert( \ + std::is_function<__VA_ARGS__>::value, \ + "Signature must be a function type, maybe return type contains " \ + "unprotected comma."); \ + static_assert( \ + ::testing::tuple_size::ArgumentTuple>::value == _N, \ + "This method does not take " GMOCK_PP_STRINGIZE( \ + _N) " arguments. Parenthesize all types with unprotected commas.") + +#define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec) + +#define GMOCK_INTERNAL_MOCK_METHOD_IMPL(_N, _MethodName, _Constness, \ + _Override, _Final, _NoexceptSpec, \ + _CallType, _RefSpec, _Signature) \ + typename ::testing::internal::Function::Result \ + GMOCK_INTERNAL_EXPAND(_CallType) \ + _MethodName(GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, _Signature, _N)) \ + GMOCK_PP_IF(_Constness, const, ) \ + _RefSpec _NoexceptSpec GMOCK_PP_IF(_Override, override, ) \ + GMOCK_PP_IF(_Final, final, ) { \ + GMOCK_MOCKER_(_N, _Constness, _MethodName) \ + .SetOwnerAndName(this, #_MethodName); \ + return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ + .Invoke(GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, _Signature, _N)); \ + } \ + ::testing::MockSpec gmock_##_MethodName( \ + GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_PARAMETER, _Signature, _N)) \ + GMOCK_PP_IF(_Constness, const, ) _RefSpec { \ + GMOCK_MOCKER_(_N, _Constness, _MethodName).RegisterOwner(this); \ + return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ + .With(GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_ARGUMENT, , _N)); \ + } \ + ::testing::MockSpec gmock_##_MethodName( \ + const ::testing::internal::WithoutMatchers&, \ + GMOCK_PP_IF(_Constness, const, )::testing::internal::Function< \ + GMOCK_PP_REMOVE_PARENS(_Signature)>*) const _RefSpec _NoexceptSpec { \ + return ::testing::internal::ThisRefAdjuster::Adjust(*this) \ + .gmock_##_MethodName(GMOCK_PP_REPEAT( \ + GMOCK_INTERNAL_A_MATCHER_ARGUMENT, _Signature, _N)); \ + } \ + mutable ::testing::FunctionMocker \ + GMOCK_MOCKER_(_N, _Constness, _MethodName) + +#define GMOCK_INTERNAL_EXPAND(...) __VA_ARGS__ + +// Valid modifiers. +#define GMOCK_INTERNAL_HAS_CONST(_Tuple) \ + GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_CONST, ~, _Tuple)) + +#define GMOCK_INTERNAL_HAS_OVERRIDE(_Tuple) \ + GMOCK_PP_HAS_COMMA( \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_OVERRIDE, ~, _Tuple)) + +#define GMOCK_INTERNAL_HAS_FINAL(_Tuple) \ + GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_FINAL, ~, _Tuple)) + +#define GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Tuple) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT, ~, _Tuple) + +#define GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT(_i, _, _elem) \ + GMOCK_PP_IF( \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)), \ + _elem, ) + +#define GMOCK_INTERNAL_GET_CALLTYPE_SPEC(_Tuple) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_CALLTYPE_SPEC_IF_CALLTYPE, ~, _Tuple) + +#define GMOCK_INTERNAL_CALLTYPE_SPEC_IF_CALLTYPE(_i, _, _elem) \ + GMOCK_PP_IF( \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem)), \ + GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), ) + +#define GMOCK_INTERNAL_GET_REF_SPEC(_Tuple) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_REF_SPEC_IF_REF, ~, _Tuple) + +#define GMOCK_INTERNAL_REF_SPEC_IF_REF(_i, _, _elem) \ + GMOCK_PP_IF(GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)), \ + GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), ) + +#ifdef GMOCK_INTERNAL_STRICT_SPEC_ASSERT +#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \ + static_assert( \ + ::testing::internal::ValidateSpec(GMOCK_PP_STRINGIZE(_elem)), \ + "Token \'" GMOCK_PP_STRINGIZE( \ + _elem) "\' cannot be recognized as a valid specification " \ + "modifier. Is a ',' missing?"); +#else +#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \ + static_assert( \ + (GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem))) == 1, \ + GMOCK_PP_STRINGIZE( \ + _elem) " cannot be recognized as a valid specification modifier."); +#endif // GMOCK_INTERNAL_STRICT_SPEC_ASSERT + +// Modifiers implementation. +#define GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CONST_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_CONST_I_const , + +#define GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_OVERRIDE_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_OVERRIDE_I_override , + +#define GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_FINAL_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_FINAL_I_final , + +#define GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_NOEXCEPT_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_NOEXCEPT_I_noexcept , + +#define GMOCK_INTERNAL_DETECT_REF(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_REF_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_REF_I_ref , + +#define GMOCK_INTERNAL_UNPACK_ref(x) x + +#define GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CALLTYPE_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_CALLTYPE_I_Calltype , + +#define GMOCK_INTERNAL_UNPACK_Calltype(...) __VA_ARGS__ + +// Note: The use of `identity_t` here allows _Ret to represent return types that +// would normally need to be specified in a different way. For example, a method +// returning a function pointer must be written as +// +// fn_ptr_return_t (*method(method_args_t...))(fn_ptr_args_t...) +// +// But we only support placing the return type at the beginning. To handle this, +// we wrap all calls in identity_t, so that a declaration will be expanded to +// +// identity_t method(method_args_t...) +// +// This allows us to work around the syntactic oddities of function/method +// types. +#define GMOCK_INTERNAL_SIGNATURE(_Ret, _Args) \ + ::testing::internal::identity_t( \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_TYPE, _, _Args)) + +#define GMOCK_INTERNAL_GET_TYPE(_i, _, _elem) \ + GMOCK_PP_COMMA_IF(_i) \ + GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_elem), GMOCK_PP_REMOVE_PARENS, \ + GMOCK_PP_IDENTITY) \ + (_elem) + +#define GMOCK_INTERNAL_PARAMETER(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + GMOCK_INTERNAL_ARG_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ + gmock_a##_i + +#define GMOCK_INTERNAL_FORWARD_ARG(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + ::std::forward(gmock_a##_i) + +#define GMOCK_INTERNAL_MATCHER_PARAMETER(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + GMOCK_INTERNAL_MATCHER_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ + gmock_a##_i + +#define GMOCK_INTERNAL_MATCHER_ARGUMENT(_i, _1, _2) \ + GMOCK_PP_COMMA_IF(_i) \ + gmock_a##_i + +#define GMOCK_INTERNAL_A_MATCHER_ARGUMENT(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + ::testing::A() + +#define GMOCK_INTERNAL_ARG_O(_i, ...) \ + typename ::testing::internal::Function<__VA_ARGS__>::template Arg<_i>::type + +#define GMOCK_INTERNAL_MATCHER_O(_i, ...) \ + const ::testing::Matcher::template Arg<_i>::type>& + +#define MOCK_METHOD0(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 0, __VA_ARGS__) +#define MOCK_METHOD1(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 1, __VA_ARGS__) +#define MOCK_METHOD2(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 2, __VA_ARGS__) +#define MOCK_METHOD3(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 3, __VA_ARGS__) +#define MOCK_METHOD4(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 4, __VA_ARGS__) +#define MOCK_METHOD5(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 5, __VA_ARGS__) +#define MOCK_METHOD6(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 6, __VA_ARGS__) +#define MOCK_METHOD7(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 7, __VA_ARGS__) +#define MOCK_METHOD8(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 8, __VA_ARGS__) +#define MOCK_METHOD9(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 9, __VA_ARGS__) +#define MOCK_METHOD10(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, , m, 10, __VA_ARGS__) + +#define MOCK_CONST_METHOD0(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 0, __VA_ARGS__) +#define MOCK_CONST_METHOD1(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 1, __VA_ARGS__) +#define MOCK_CONST_METHOD2(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 2, __VA_ARGS__) +#define MOCK_CONST_METHOD3(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 3, __VA_ARGS__) +#define MOCK_CONST_METHOD4(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 4, __VA_ARGS__) +#define MOCK_CONST_METHOD5(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 5, __VA_ARGS__) +#define MOCK_CONST_METHOD6(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 6, __VA_ARGS__) +#define MOCK_CONST_METHOD7(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 7, __VA_ARGS__) +#define MOCK_CONST_METHOD8(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 8, __VA_ARGS__) +#define MOCK_CONST_METHOD9(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 9, __VA_ARGS__) +#define MOCK_CONST_METHOD10(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 10, __VA_ARGS__) + +#define MOCK_METHOD0_T(m, ...) MOCK_METHOD0(m, __VA_ARGS__) +#define MOCK_METHOD1_T(m, ...) MOCK_METHOD1(m, __VA_ARGS__) +#define MOCK_METHOD2_T(m, ...) MOCK_METHOD2(m, __VA_ARGS__) +#define MOCK_METHOD3_T(m, ...) MOCK_METHOD3(m, __VA_ARGS__) +#define MOCK_METHOD4_T(m, ...) MOCK_METHOD4(m, __VA_ARGS__) +#define MOCK_METHOD5_T(m, ...) MOCK_METHOD5(m, __VA_ARGS__) +#define MOCK_METHOD6_T(m, ...) MOCK_METHOD6(m, __VA_ARGS__) +#define MOCK_METHOD7_T(m, ...) MOCK_METHOD7(m, __VA_ARGS__) +#define MOCK_METHOD8_T(m, ...) MOCK_METHOD8(m, __VA_ARGS__) +#define MOCK_METHOD9_T(m, ...) MOCK_METHOD9(m, __VA_ARGS__) +#define MOCK_METHOD10_T(m, ...) MOCK_METHOD10(m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T(m, ...) MOCK_CONST_METHOD0(m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T(m, ...) MOCK_CONST_METHOD1(m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T(m, ...) MOCK_CONST_METHOD2(m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T(m, ...) MOCK_CONST_METHOD3(m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T(m, ...) MOCK_CONST_METHOD4(m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T(m, ...) MOCK_CONST_METHOD5(m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T(m, ...) MOCK_CONST_METHOD6(m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T(m, ...) MOCK_CONST_METHOD7(m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T(m, ...) MOCK_CONST_METHOD8(m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T(m, ...) MOCK_CONST_METHOD9(m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T(m, ...) MOCK_CONST_METHOD10(m, __VA_ARGS__) + +#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 0, __VA_ARGS__) +#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 1, __VA_ARGS__) +#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 2, __VA_ARGS__) +#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 3, __VA_ARGS__) +#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 4, __VA_ARGS__) +#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 5, __VA_ARGS__) +#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 6, __VA_ARGS__) +#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 7, __VA_ARGS__) +#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 8, __VA_ARGS__) +#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 9, __VA_ARGS__) +#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 10, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 0, __VA_ARGS__) +#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 1, __VA_ARGS__) +#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 2, __VA_ARGS__) +#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 3, __VA_ARGS__) +#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 4, __VA_ARGS__) +#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 5, __VA_ARGS__) +#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 6, __VA_ARGS__) +#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 7, __VA_ARGS__) +#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 8, __VA_ARGS__) +#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 9, __VA_ARGS__) +#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 10, __VA_ARGS__) + +#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHODN(constness, ct, Method, args_num, ...) \ + GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ + args_num, ::testing::internal::identity_t<__VA_ARGS__>); \ + GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ + args_num, Method, GMOCK_PP_NARG0(constness), 0, 0, , ct, , \ + (::testing::internal::identity_t<__VA_ARGS__>)) + +#define GMOCK_MOCKER_(arity, constness, Method) \ + GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) + +#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_ diff --git a/GTest/include/gmock/gmock-matchers.h b/GTest/include/gmock/gmock-matchers.h new file mode 100644 index 0000000..2ae2499 --- /dev/null +++ b/GTest/include/gmock/gmock-matchers.h @@ -0,0 +1,5677 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// The MATCHER* family of macros can be used in a namespace scope to +// define custom matchers easily. +// +// Basic Usage +// =========== +// +// The syntax +// +// MATCHER(name, description_string) { statements; } +// +// defines a matcher with the given name that executes the statements, +// which must return a bool to indicate if the match succeeds. Inside +// the statements, you can refer to the value being matched by 'arg', +// and refer to its type by 'arg_type'. +// +// The description string documents what the matcher does, and is used +// to generate the failure message when the match fails. Since a +// MATCHER() is usually defined in a header file shared by multiple +// C++ source files, we require the description to be a C-string +// literal to avoid possible side effects. It can be empty, in which +// case we'll use the sequence of words in the matcher name as the +// description. +// +// For example: +// +// MATCHER(IsEven, "") { return (arg % 2) == 0; } +// +// allows you to write +// +// // Expects mock_foo.Bar(n) to be called where n is even. +// EXPECT_CALL(mock_foo, Bar(IsEven())); +// +// or, +// +// // Verifies that the value of some_expression is even. +// EXPECT_THAT(some_expression, IsEven()); +// +// If the above assertion fails, it will print something like: +// +// Value of: some_expression +// Expected: is even +// Actual: 7 +// +// where the description "is even" is automatically calculated from the +// matcher name IsEven. +// +// Argument Type +// ============= +// +// Note that the type of the value being matched (arg_type) is +// determined by the context in which you use the matcher and is +// supplied to you by the compiler, so you don't need to worry about +// declaring it (nor can you). This allows the matcher to be +// polymorphic. For example, IsEven() can be used to match any type +// where the value of "(arg % 2) == 0" can be implicitly converted to +// a bool. In the "Bar(IsEven())" example above, if method Bar() +// takes an int, 'arg_type' will be int; if it takes an unsigned long, +// 'arg_type' will be unsigned long; and so on. +// +// Parameterizing Matchers +// ======================= +// +// Sometimes you'll want to parameterize the matcher. For that you +// can use another macro: +// +// MATCHER_P(name, param_name, description_string) { statements; } +// +// For example: +// +// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +// +// will allow you to write: +// +// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +// +// which may lead to this message (assuming n is 10): +// +// Value of: Blah("a") +// Expected: has absolute value 10 +// Actual: -9 +// +// Note that both the matcher description and its parameter are +// printed, making the message human-friendly. +// +// In the matcher definition body, you can write 'foo_type' to +// reference the type of a parameter named 'foo'. For example, in the +// body of MATCHER_P(HasAbsoluteValue, value) above, you can write +// 'value_type' to refer to the type of 'value'. +// +// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to +// support multi-parameter matchers. +// +// Describing Parameterized Matchers +// ================================= +// +// The last argument to MATCHER*() is a string-typed expression. The +// expression can reference all of the matcher's parameters and a +// special bool-typed variable named 'negation'. When 'negation' is +// false, the expression should evaluate to the matcher's description; +// otherwise it should evaluate to the description of the negation of +// the matcher. For example, +// +// using testing::PrintToString; +// +// MATCHER_P2(InClosedRange, low, hi, +// std::string(negation ? "is not" : "is") + " in range [" + +// PrintToString(low) + ", " + PrintToString(hi) + "]") { +// return low <= arg && arg <= hi; +// } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: is in range [4, 6] +// ... +// Expected: is not in range [2, 4] +// +// If you specify "" as the description, the failure message will +// contain the sequence of words in the matcher name followed by the +// parameter values printed as a tuple. For example, +// +// MATCHER_P2(InClosedRange, low, hi, "") { ... } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: in closed range (4, 6) +// ... +// Expected: not (in closed range (2, 4)) +// +// Types of Matcher Parameters +// =========================== +// +// For the purpose of typing, you can view +// +// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +// +// as shorthand for +// +// template +// FooMatcherPk +// Foo(p1_type p1, ..., pk_type pk) { ... } +// +// When you write Foo(v1, ..., vk), the compiler infers the types of +// the parameters v1, ..., and vk for you. If you are not happy with +// the result of the type inference, you can specify the types by +// explicitly instantiating the template, as in Foo(5, +// false). As said earlier, you don't get to (or need to) specify +// 'arg_type' as that's determined by the context in which the matcher +// is used. You can assign the result of expression Foo(p1, ..., pk) +// to a variable of type FooMatcherPk. This +// can be useful when composing matchers. +// +// While you can instantiate a matcher template with reference types, +// passing the parameters by pointer usually makes your code more +// readable. If, however, you still want to pass a parameter by +// reference, be aware that in the failure message generated by the +// matcher you will see the value of the referenced object but not its +// address. +// +// Explaining Match Results +// ======================== +// +// Sometimes the matcher description alone isn't enough to explain why +// the match has failed or succeeded. For example, when expecting a +// long string, it can be very helpful to also print the diff between +// the expected string and the actual one. To achieve that, you can +// optionally stream additional information to a special variable +// named result_listener, whose type is a pointer to class +// MatchResultListener: +// +// MATCHER_P(EqualsLongString, str, "") { +// if (arg == str) return true; +// +// *result_listener << "the difference: " +/// << DiffStrings(str, arg); +// return false; +// } +// +// Overloading Matchers +// ==================== +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// Caveats +// ======= +// +// When defining a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher(). These +// approaches require more work than the MATCHER* macros, but also +// give you more control on the types of the value being matched and +// the matcher parameters, which may leads to better compiler error +// messages when the matcher is used wrong. They also allow +// overloading matchers based on parameter types (as opposed to just +// based on the number of parameters). +// +// MATCHER*() can only be used in a namespace scope as templates cannot be +// declared inside of a local class. +// +// More Information +// ================ +// +// To learn more about using these macros, please search for 'MATCHER' +// on +// https://github.com/google/googletest/blob/main/docs/gmock_cook_book.md +// +// This file also implements some commonly used argument matchers. More +// matchers can be defined by the user implementing the +// MatcherInterface interface if necessary. +// +// See googletest/include/gtest/gtest-matchers.h for the definition of class +// Matcher, class MatcherInterface, and others. + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // NOLINT +#include +#include +#include +#include +#include + +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" +#include "gmock/internal/gmock-pp.h" +#include "gtest/gtest.h" + +// MSVC warning C5046 is new as of VS2017 version 15.8. +#if defined(_MSC_VER) && _MSC_VER >= 1915 +#define GMOCK_MAYBE_5046_ 5046 +#else +#define GMOCK_MAYBE_5046_ +#endif + +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4251 GMOCK_MAYBE_5046_ /* class A needs to have dll-interface to be used by + clients of class B */ + /* Symbol involving type with internal linkage not defined */) + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherImpl that implements the +// MatcherInterface interface, and +// 2. a factory function that creates a Matcher object from a +// FooMatcherImpl*. +// +// The two-level delegation design makes it possible to allow a user +// to write "v" instead of "Eq(v)" where a Matcher is expected, which +// is impossible if we pass matchers by pointers. It also eases +// ownership management as Matcher objects can now be copied like +// plain values. + +// A match result listener that stores the explanation in a string. +class StringMatchResultListener : public MatchResultListener { + public: + StringMatchResultListener() : MatchResultListener(&ss_) {} + + // Returns the explanation accumulated so far. + std::string str() const { return ss_.str(); } + + // Clears the explanation accumulated so far. + void Clear() { ss_.str(""); } + + private: + ::std::stringstream ss_; + + StringMatchResultListener(const StringMatchResultListener&) = delete; + StringMatchResultListener& operator=(const StringMatchResultListener&) = + delete; +}; + +// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION +// and MUST NOT BE USED IN USER CODE!!! +namespace internal { + +// The MatcherCastImpl class template is a helper for implementing +// MatcherCast(). We need this helper in order to partially +// specialize the implementation of MatcherCast() (C++ allows +// class/struct templates to be partially specialized, but not +// function templates.). + +// This general version is used when MatcherCast()'s argument is a +// polymorphic matcher (i.e. something that can be converted to a +// Matcher but is not one yet; for example, Eq(value)) or a value (for +// example, "hello"). +template +class MatcherCastImpl { + public: + static Matcher Cast(const M& polymorphic_matcher_or_value) { + // M can be a polymorphic matcher, in which case we want to use + // its conversion operator to create Matcher. Or it can be a value + // that should be passed to the Matcher's constructor. + // + // We can't call Matcher(polymorphic_matcher_or_value) when M is a + // polymorphic matcher because it'll be ambiguous if T has an implicit + // constructor from M (this usually happens when T has an implicit + // constructor from any type). + // + // It won't work to unconditionally implicit_cast + // polymorphic_matcher_or_value to Matcher because it won't trigger + // a user-defined conversion from M to T if one exists (assuming M is + // a value). + return CastImpl(polymorphic_matcher_or_value, + std::is_convertible>{}, + std::is_convertible{}); + } + + private: + template + static Matcher CastImpl(const M& polymorphic_matcher_or_value, + std::true_type /* convertible_to_matcher */, + std::integral_constant) { + // M is implicitly convertible to Matcher, which means that either + // M is a polymorphic matcher or Matcher has an implicit constructor + // from M. In both cases using the implicit conversion will produce a + // matcher. + // + // Even if T has an implicit constructor from M, it won't be called because + // creating Matcher would require a chain of two user-defined conversions + // (first to create T from M and then to create Matcher from T). + return polymorphic_matcher_or_value; + } + + // M can't be implicitly converted to Matcher, so M isn't a polymorphic + // matcher. It's a value of a type implicitly convertible to T. Use direct + // initialization to create a matcher. + static Matcher CastImpl(const M& value, + std::false_type /* convertible_to_matcher */, + std::true_type /* convertible_to_T */) { + return Matcher(ImplicitCast_(value)); + } + + // M can't be implicitly converted to either Matcher or T. Attempt to use + // polymorphic matcher Eq(value) in this case. + // + // Note that we first attempt to perform an implicit cast on the value and + // only fall back to the polymorphic Eq() matcher afterwards because the + // latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end + // which might be undefined even when Rhs is implicitly convertible to Lhs + // (e.g. std::pair vs. std::pair). + // + // We don't define this method inline as we need the declaration of Eq(). + static Matcher CastImpl(const M& value, + std::false_type /* convertible_to_matcher */, + std::false_type /* convertible_to_T */); +}; + +// This more specialized version is used when MatcherCast()'s argument +// is already a Matcher. This only compiles when type T can be +// statically converted to type U. +template +class MatcherCastImpl> { + public: + static Matcher Cast(const Matcher& source_matcher) { + return Matcher(new Impl(source_matcher)); + } + + private: + class Impl : public MatcherInterface { + public: + explicit Impl(const Matcher& source_matcher) + : source_matcher_(source_matcher) {} + + // We delegate the matching logic to the source matcher. + bool MatchAndExplain(T x, MatchResultListener* listener) const override { + using FromType = typename std::remove_cv::type>::type>::type; + using ToType = typename std::remove_cv::type>::type>::type; + // Do not allow implicitly converting base*/& to derived*/&. + static_assert( + // Do not trigger if only one of them is a pointer. That implies a + // regular conversion and not a down_cast. + (std::is_pointer::type>::value != + std::is_pointer::type>::value) || + std::is_same::value || + !std::is_base_of::value, + "Can't implicitly convert from to "); + + // Do the cast to `U` explicitly if necessary. + // Otherwise, let implicit conversions do the trick. + using CastType = + typename std::conditional::value, + T&, U>::type; + + return source_matcher_.MatchAndExplain(static_cast(x), + listener); + } + + void DescribeTo(::std::ostream* os) const override { + source_matcher_.DescribeTo(os); + } + + void DescribeNegationTo(::std::ostream* os) const override { + source_matcher_.DescribeNegationTo(os); + } + + private: + const Matcher source_matcher_; + }; +}; + +// This even more specialized version is used for efficiently casting +// a matcher to its own type. +template +class MatcherCastImpl> { + public: + static Matcher Cast(const Matcher& matcher) { return matcher; } +}; + +// Template specialization for parameterless Matcher. +template +class MatcherBaseImpl { + public: + MatcherBaseImpl() = default; + + template + operator ::testing::Matcher() const { // NOLINT(runtime/explicit) + return ::testing::Matcher(new + typename Derived::template gmock_Impl()); + } +}; + +// Template specialization for Matcher with parameters. +template