From dfe62dcf8bcefc523b466e127c3edc4dc2756629 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 6 Oct 2024 13:57:39 +0800 Subject: Rename common to base. --- demos/Graphics/DrawCircle/DrawCircle.cpp | 2 +- include/cru/base/Base.h | 112 ++++ include/cru/base/Bitmask.h | 55 ++ include/cru/base/Buffer.h | 161 +++++ include/cru/base/ClonablePtr.h | 216 +++++++ include/cru/base/Event.h | 281 +++++++++ include/cru/base/Event2.h | 200 ++++++ include/cru/base/Exception.h | 60 ++ include/cru/base/Format.h | 154 +++++ include/cru/base/Guard.h | 26 + include/cru/base/HandlerRegistry.h | 87 +++ include/cru/base/PreConfig.h | 18 + include/cru/base/PropertyTree.h | 63 ++ include/cru/base/Range.h | 42 ++ include/cru/base/SelfResolvable.h | 153 +++++ include/cru/base/String.h | 492 +++++++++++++++ include/cru/base/StringToNumberConverter.h | 107 ++++ include/cru/base/StringUtil.h | 226 +++++++ include/cru/base/SubProcess.h | 258 ++++++++ include/cru/base/concurrent/ConcurrentQueue.h | 88 +++ include/cru/base/io/AutoReadStream.h | 72 +++ include/cru/base/io/BufferStream.h | 85 +++ include/cru/base/io/CFileStream.h | 39 ++ include/cru/base/io/MemoryStream.h | 36 ++ include/cru/base/io/OpenFileFlag.h | 56 ++ include/cru/base/io/ProxyStream.h | 42 ++ include/cru/base/io/Resource.h | 8 + include/cru/base/io/Stream.h | 126 ++++ include/cru/base/log/Logger.h | 88 +++ include/cru/base/log/StdioLogTarget.h | 17 + include/cru/base/platform/Exception.h | 12 + include/cru/base/platform/osx/Convert.h | 18 + include/cru/base/platform/osx/Exception.h | 15 + .../cru/base/platform/unix/PosixSpawnSubProcess.h | 50 ++ include/cru/base/platform/unix/UnixFileStream.h | 39 ++ include/cru/base/platform/unix/UnixPipe.h | 70 +++ include/cru/base/platform/web/WebException.h | 16 + include/cru/base/platform/win/ComAutoInit.h | 21 + include/cru/base/platform/win/DebugLogTarget.h | 25 + include/cru/base/platform/win/Exception.h | 56 ++ include/cru/base/platform/win/StreamConvert.h | 14 + include/cru/base/platform/win/Win32FileStream.h | 56 ++ include/cru/base/platform/win/WinPreConfig.h | 13 + include/cru/common/Base.h | 112 ---- include/cru/common/Bitmask.h | 55 -- include/cru/common/Buffer.h | 161 ----- include/cru/common/ClonablePtr.h | 216 ------- include/cru/common/Event.h | 281 --------- include/cru/common/Event2.h | 200 ------ include/cru/common/Exception.h | 60 -- include/cru/common/Format.h | 154 ----- include/cru/common/Guard.h | 26 - include/cru/common/HandlerRegistry.h | 87 --- include/cru/common/PreConfig.h | 18 - include/cru/common/PropertyTree.h | 63 -- include/cru/common/Range.h | 42 -- include/cru/common/SelfResolvable.h | 153 ----- include/cru/common/String.h | 492 --------------- include/cru/common/StringToNumberConverter.h | 107 ---- include/cru/common/StringUtil.h | 226 ------- include/cru/common/SubProcess.h | 258 -------- include/cru/common/concurrent/ConcurrentQueue.h | 88 --- include/cru/common/io/AutoReadStream.h | 72 --- include/cru/common/io/BufferStream.h | 85 --- include/cru/common/io/CFileStream.h | 39 -- include/cru/common/io/MemoryStream.h | 36 -- include/cru/common/io/OpenFileFlag.h | 56 -- include/cru/common/io/ProxyStream.h | 42 -- include/cru/common/io/Resource.h | 8 - include/cru/common/io/Stream.h | 126 ---- include/cru/common/log/Logger.h | 88 --- include/cru/common/log/StdioLogTarget.h | 17 - include/cru/common/platform/Exception.h | 12 - include/cru/common/platform/osx/Convert.h | 18 - include/cru/common/platform/osx/Exception.h | 15 - .../common/platform/unix/PosixSpawnSubProcess.h | 50 -- include/cru/common/platform/unix/UnixFileStream.h | 39 -- include/cru/common/platform/unix/UnixPipe.h | 70 --- include/cru/common/platform/web/WebException.h | 16 - include/cru/common/platform/win/ComAutoInit.h | 21 - include/cru/common/platform/win/DebugLogTarget.h | 25 - include/cru/common/platform/win/Exception.h | 56 -- include/cru/common/platform/win/StreamConvert.h | 14 - include/cru/common/platform/win/Win32FileStream.h | 56 -- include/cru/common/platform/win/WinPreConfig.h | 13 - include/cru/parse/Production.h | 2 +- include/cru/parse/Symbol.h | 2 +- include/cru/parse/TokenType.h | 4 +- include/cru/platform/Check.h | 2 +- include/cru/platform/Color.h | 6 +- include/cru/platform/Exception.h | 6 +- include/cru/platform/GraphicsBase.h | 6 +- include/cru/platform/Resource.h | 4 +- include/cru/platform/graphics/ImageFactory.h | 2 +- include/cru/platform/graphics/NullPainter.h | 2 +- .../platform/graphics/SvgGeometryBuilderMixin.h | 2 +- .../cru/platform/graphics/direct2d/ComResource.h | 2 +- include/cru/platform/graphics/direct2d/Factory.h | 2 +- include/cru/platform/graphics/direct2d/Painter.h | 2 +- include/cru/platform/graphics/quartz/Brush.h | 2 +- include/cru/platform/graphics/quartz/Convert.h | 6 +- include/cru/platform/graphics/quartz/Factory.h | 2 +- include/cru/platform/graphics/quartz/Font.h | 2 +- include/cru/platform/graphics/quartz/Painter.h | 2 +- include/cru/platform/graphics/quartz/TextLayout.h | 2 +- .../platform/graphics/web_canvas/WebCanvasRef.h | 2 +- .../graphics/web_canvas/WebCanvasResource.h | 2 +- include/cru/platform/gui/Base.h | 4 +- include/cru/platform/gui/InputMethod.h | 2 +- include/cru/platform/gui/Keyboard.h | 2 +- include/cru/platform/gui/UiApplication.h | 2 +- include/cru/platform/gui/Window.h | 2 +- include/cru/platform/gui/win/Base.h | 2 +- include/cru/platform/gui/win/Clipboard.h | 2 +- include/cru/platform/gui/win/GodWindow.h | 4 +- .../gui/win/WindowNativeMessageEventArgs.h | 2 +- include/cru/platform/osx/Convert.h | 2 +- include/cru/platform/osx/Exception.h | 2 +- include/cru/platform/win/Exception.h | 2 +- include/cru/platform/win/WinPreConfig.h | 2 +- include/cru/toml/TomlDocument.h | 4 +- include/cru/toml/TomlParser.h | 2 +- include/cru/ui/Base.h | 2 +- include/cru/ui/ThemeManager.h | 2 +- include/cru/ui/ThemeResourceDictionary.h | 2 +- include/cru/ui/components/Component.h | 2 +- include/cru/ui/components/Menu.h | 2 +- include/cru/ui/controls/Button.h | 2 +- include/cru/ui/controls/Control.h | 2 +- include/cru/ui/controls/IBorderControl.h | 2 +- include/cru/ui/controls/ICheckableControl.h | 2 +- include/cru/ui/controls/IClickableControl.h | 2 +- include/cru/ui/controls/IconButton.h | 2 +- include/cru/ui/controls/RootControl.h | 2 +- include/cru/ui/controls/Window.h | 2 +- include/cru/ui/document/DocumentElementType.h | 2 +- include/cru/ui/document/TextDocumentElement.h | 4 +- include/cru/ui/events/RoutedEvent.h | 2 +- include/cru/ui/helper/ClickDetector.h | 2 +- include/cru/ui/helper/ShortcutHub.h | 4 +- include/cru/ui/host/WindowHost.h | 2 +- include/cru/ui/mapper/BrushMapper.h | 2 +- include/cru/ui/mapper/FontMapper.h | 2 +- include/cru/ui/mapper/Mapper.h | 4 +- include/cru/ui/mapper/ThicknessMapper.h | 2 +- include/cru/ui/mapper/style/BorderStylerMapper.h | 2 +- include/cru/ui/mapper/style/IConditionMapper.h | 2 +- include/cru/ui/mapper/style/IStylerMapper.h | 2 +- include/cru/ui/mapper/style/NoConditionMapper.h | 4 +- include/cru/ui/mapper/style/StyleRuleMapper.h | 4 +- include/cru/ui/model/IListChangeNotify.h | 4 +- include/cru/ui/render/CanvasRenderObject.h | 2 +- include/cru/ui/render/MeasureRequirement.h | 2 +- include/cru/ui/render/RenderObject.h | 2 +- include/cru/ui/render/ScrollBar.h | 4 +- include/cru/ui/render/ScrollRenderObject.h | 2 +- include/cru/ui/style/Condition.h | 6 +- include/cru/ui/style/StyleRule.h | 2 +- include/cru/ui/style/StyleRuleSet.h | 4 +- include/cru/ui/style/Styler.h | 2 +- include/cru/xml/XmlNode.h | 2 +- include/cru/xml/XmlParser.h | 4 +- src/CMakeLists.txt | 4 +- src/ThemeBuilder/components/Editor.h | 2 +- src/ThemeBuilder/components/HeadBodyEditor.h | 2 +- src/ThemeBuilder/components/StyleRuleSetEditor.cpp | 4 +- .../conditions/CheckedConditionEditor.cpp | 2 +- .../components/conditions/CheckedConditionEditor.h | 2 +- .../conditions/ClickStateConditionEditor.cpp | 2 +- .../conditions/ClickStateConditionEditor.h | 4 +- .../conditions/CompoundConditionEditor.cpp | 2 +- .../conditions/CompoundConditionEditor.h | 4 +- .../components/conditions/ConditionEditor.cpp | 2 +- .../components/conditions/FocusConditionEditor.cpp | 2 +- .../components/conditions/FocusConditionEditor.h | 2 +- .../components/conditions/NoConditionEditor.h | 2 +- .../properties/MeasureLengthPropertyEditor.cpp | 2 +- .../components/properties/PointPropertyEditor.cpp | 2 +- .../components/stylers/BorderStylerEditor.cpp | 2 +- .../components/stylers/BorderStylerEditor.h | 2 +- .../components/stylers/CompoundStylerEditor.cpp | 2 +- .../components/stylers/CompoundStylerEditor.h | 2 +- .../components/stylers/ContentBrushStylerEditor.h | 2 +- .../components/stylers/FontStylerEditor.h | 2 +- .../components/stylers/MarginStylerEditor.h | 2 +- .../components/stylers/PaddingStylerEditor.h | 2 +- .../components/stylers/PreferredSizeStylerEditor.h | 2 +- src/ThemeBuilder/main.cpp | 2 +- src/base/Base.cpp | 7 + src/base/Buffer.cpp | 277 +++++++++ src/base/CMakeLists.txt | 80 +++ src/base/Exception.cpp | 36 ++ src/base/Format.cpp | 111 ++++ src/base/PropertyTree.cpp | 71 +++ src/base/String.cpp | 672 +++++++++++++++++++++ src/base/StringToNumberConverter.cpp | 170 ++++++ src/base/StringUtil.cpp | 243 ++++++++ src/base/SubProcess.cpp | 209 +++++++ src/base/io/AutoReadStream.cpp | 56 ++ src/base/io/BufferStream.cpp | 109 ++++ src/base/io/CFileStream.cpp | 96 +++ src/base/io/MemoryStream.cpp | 74 +++ src/base/io/OpenFileFlag.cpp | 19 + src/base/io/ProxyStream.cpp | 37 ++ src/base/io/Resource.cpp | 48 ++ src/base/io/Stream.cpp | 199 ++++++ src/base/log/Logger.cpp | 88 +++ src/base/log/StdioLogTarget.cpp | 27 + src/base/platform/Exception.cpp | 1 + src/base/platform/osx/Convert.cpp | 29 + src/base/platform/osx/Exception.cpp | 1 + src/base/platform/unix/PosixSpawnSubProcess.cpp | 204 +++++++ src/base/platform/unix/UnixFileStream.cpp | 106 ++++ src/base/platform/unix/UnixPipe.cpp | 51 ++ src/base/platform/web/WebException.cpp | 1 + src/base/platform/win/BridgeComStream.cpp | 106 ++++ src/base/platform/win/BrigdeComStream.h | 43 ++ src/base/platform/win/ComAutoInit.cpp | 15 + src/base/platform/win/DebugLogTarget.cpp | 10 + src/base/platform/win/Exception.cpp | 38 ++ src/base/platform/win/StreamConvert.cpp | 28 + src/base/platform/win/Win32FileStream.cpp | 122 ++++ src/base/platform/win/Win32FileStreamPrivate.h | 13 + src/common/Base.cpp | 7 - src/common/Buffer.cpp | 277 --------- src/common/CMakeLists.txt | 80 --- src/common/Exception.cpp | 36 -- src/common/Format.cpp | 111 ---- src/common/PropertyTree.cpp | 71 --- src/common/String.cpp | 672 --------------------- src/common/StringToNumberConverter.cpp | 170 ------ src/common/StringUtil.cpp | 243 -------- src/common/SubProcess.cpp | 209 ------- src/common/io/AutoReadStream.cpp | 56 -- src/common/io/BufferStream.cpp | 109 ---- src/common/io/CFileStream.cpp | 96 --- src/common/io/MemoryStream.cpp | 74 --- src/common/io/OpenFileFlag.cpp | 19 - src/common/io/ProxyStream.cpp | 37 -- src/common/io/Resource.cpp | 48 -- src/common/io/Stream.cpp | 199 ------ src/common/log/Logger.cpp | 88 --- src/common/log/StdioLogTarget.cpp | 27 - src/common/platform/Exception.cpp | 1 - src/common/platform/osx/Convert.cpp | 29 - src/common/platform/osx/Exception.cpp | 1 - src/common/platform/unix/PosixSpawnSubProcess.cpp | 204 ------- src/common/platform/unix/UnixFileStream.cpp | 106 ---- src/common/platform/unix/UnixPipe.cpp | 51 -- src/common/platform/web/WebException.cpp | 1 - src/common/platform/win/BridgeComStream.cpp | 106 ---- src/common/platform/win/BrigdeComStream.h | 43 -- src/common/platform/win/ComAutoInit.cpp | 15 - src/common/platform/win/DebugLogTarget.cpp | 10 - src/common/platform/win/Exception.cpp | 38 -- src/common/platform/win/StreamConvert.cpp | 28 - src/common/platform/win/Win32FileStream.cpp | 122 ---- src/common/platform/win/Win32FileStreamPrivate.h | 13 - src/parse/Grammar.cpp | 4 +- src/platform/Exception.cpp | 2 +- src/platform/graphics/Geometry.cpp | 2 +- src/platform/graphics/cairo/CairoImageFactory.cpp | 2 +- src/platform/graphics/cairo/CairoPainter.cpp | 2 +- src/platform/graphics/cairo/PangoTextLayout.cpp | 2 +- src/platform/graphics/direct2d/Factory.cpp | 2 +- src/platform/graphics/direct2d/Font.cpp | 2 +- src/platform/graphics/direct2d/Geometry.cpp | 2 +- src/platform/graphics/direct2d/Image.cpp | 2 +- src/platform/graphics/direct2d/ImageFactory.cpp | 4 +- src/platform/graphics/direct2d/Painter.cpp | 2 +- src/platform/graphics/direct2d/TextLayout.cpp | 2 +- src/platform/graphics/quartz/Brush.cpp | 4 +- src/platform/graphics/quartz/Image.cpp | 2 +- src/platform/graphics/quartz/ImageFactory.cpp | 4 +- src/platform/graphics/quartz/TextLayout.cpp | 6 +- src/platform/gui/osx/Clipboard.mm | 2 +- src/platform/gui/osx/ClipboardPrivate.h | 2 +- src/platform/gui/osx/InputMethod.mm | 2 +- src/platform/gui/osx/Menu.mm | 2 +- src/platform/gui/osx/UiApplication.mm | 4 +- src/platform/gui/osx/Window.mm | 4 +- src/platform/gui/osx/WindowPrivate.h | 2 +- src/platform/gui/win/Clipboard.cpp | 2 +- src/platform/gui/win/Cursor.cpp | 2 +- src/platform/gui/win/GodWindow.cpp | 2 +- src/platform/gui/win/InputMethod.cpp | 4 +- src/platform/gui/win/TimerManager.h | 4 +- src/platform/gui/win/UiApplication.cpp | 2 +- src/platform/gui/win/Window.cpp | 2 +- src/platform/gui/win/WindowManager.h | 2 +- src/ui/ThemeManager.cpp | 4 +- src/ui/ThemeResourceDictionary.cpp | 4 +- src/ui/components/Input.cpp | 2 +- src/ui/controls/Control.cpp | 2 +- src/ui/controls/RootControl.cpp | 2 +- src/ui/controls/TextHostControlService.cpp | 8 +- src/ui/document/TextDocumentElement.cpp | 2 +- src/ui/helper/ClickDetector.cpp | 2 +- src/ui/helper/ShortcutHub.cpp | 2 +- src/ui/host/RoutedEventDispatch.h | 4 +- src/ui/host/WindowHost.cpp | 4 +- src/ui/mapper/BorderStyleMapper.cpp | 2 +- src/ui/mapper/CursorMapper.cpp | 2 +- src/ui/mapper/style/AndConditionMapper.cpp | 2 +- src/ui/mapper/style/BorderStylerMapper.cpp | 2 +- src/ui/mapper/style/CheckedConditionMapper.cpp | 2 +- src/ui/mapper/style/ClickStateConditionMapper.cpp | 4 +- src/ui/mapper/style/ContentBrushStylerMapper.cpp | 2 +- src/ui/mapper/style/CursorStylerMapper.cpp | 2 +- src/ui/mapper/style/FocusConditionMapper.cpp | 2 +- src/ui/mapper/style/FontStylerMapper.cpp | 2 +- src/ui/mapper/style/HoverConditionMapper.cpp | 2 +- src/ui/mapper/style/NoConditionMapper.cpp | 2 +- src/ui/mapper/style/OrConditionMapper.cpp | 2 +- src/ui/mapper/style/StyleRuleMapper.cpp | 6 +- src/ui/render/BorderRenderObject.cpp | 2 +- src/ui/render/FlexLayoutRenderObject.cpp | 2 +- src/ui/render/LayoutHelper.cpp | 2 +- src/ui/render/RenderObject.cpp | 4 +- src/ui/render/ScrollBar.cpp | 2 +- src/ui/render/StackLayoutRenderObject.cpp | 2 +- src/ui/render/TextRenderObject.cpp | 2 +- src/ui/style/Condition.cpp | 4 +- src/ui/style/StyleRuleSet.cpp | 2 +- src/ui/style/Styler.cpp | 2 +- test/common/Event2Test.cpp | 2 +- test/common/HandlerRegistryTest.cpp | 2 +- test/common/PropertyTreeTest.cpp | 2 +- test/common/SelfResolvableTest.cpp | 4 +- test/common/StringTest.cpp | 4 +- test/common/StringToNumberConverterTest.cpp | 4 +- test/common/StringUtilTest.cpp | 4 +- test/common/SubProcessTest.cpp | 4 +- test/common/platform/unix/UnixFileStreamTest.cpp | 2 +- test/common/platform/win/StreamConvertTest.cpp | 8 +- test/common/platform/win/Win32FileStreamTest.cpp | 4 +- 336 files changed, 7410 insertions(+), 7412 deletions(-) create mode 100644 include/cru/base/Base.h create mode 100644 include/cru/base/Bitmask.h create mode 100644 include/cru/base/Buffer.h create mode 100644 include/cru/base/ClonablePtr.h create mode 100644 include/cru/base/Event.h create mode 100644 include/cru/base/Event2.h create mode 100644 include/cru/base/Exception.h create mode 100644 include/cru/base/Format.h create mode 100644 include/cru/base/Guard.h create mode 100644 include/cru/base/HandlerRegistry.h create mode 100644 include/cru/base/PreConfig.h create mode 100644 include/cru/base/PropertyTree.h create mode 100644 include/cru/base/Range.h create mode 100644 include/cru/base/SelfResolvable.h create mode 100644 include/cru/base/String.h create mode 100644 include/cru/base/StringToNumberConverter.h create mode 100644 include/cru/base/StringUtil.h create mode 100644 include/cru/base/SubProcess.h create mode 100644 include/cru/base/concurrent/ConcurrentQueue.h create mode 100644 include/cru/base/io/AutoReadStream.h create mode 100644 include/cru/base/io/BufferStream.h create mode 100644 include/cru/base/io/CFileStream.h create mode 100644 include/cru/base/io/MemoryStream.h create mode 100644 include/cru/base/io/OpenFileFlag.h create mode 100644 include/cru/base/io/ProxyStream.h create mode 100644 include/cru/base/io/Resource.h create mode 100644 include/cru/base/io/Stream.h create mode 100644 include/cru/base/log/Logger.h create mode 100644 include/cru/base/log/StdioLogTarget.h create mode 100644 include/cru/base/platform/Exception.h create mode 100644 include/cru/base/platform/osx/Convert.h create mode 100644 include/cru/base/platform/osx/Exception.h create mode 100644 include/cru/base/platform/unix/PosixSpawnSubProcess.h create mode 100644 include/cru/base/platform/unix/UnixFileStream.h create mode 100644 include/cru/base/platform/unix/UnixPipe.h create mode 100644 include/cru/base/platform/web/WebException.h create mode 100644 include/cru/base/platform/win/ComAutoInit.h create mode 100644 include/cru/base/platform/win/DebugLogTarget.h create mode 100644 include/cru/base/platform/win/Exception.h create mode 100644 include/cru/base/platform/win/StreamConvert.h create mode 100644 include/cru/base/platform/win/Win32FileStream.h create mode 100644 include/cru/base/platform/win/WinPreConfig.h delete mode 100644 include/cru/common/Base.h delete mode 100644 include/cru/common/Bitmask.h delete mode 100644 include/cru/common/Buffer.h delete mode 100644 include/cru/common/ClonablePtr.h delete mode 100644 include/cru/common/Event.h delete mode 100644 include/cru/common/Event2.h delete mode 100644 include/cru/common/Exception.h delete mode 100644 include/cru/common/Format.h delete mode 100644 include/cru/common/Guard.h delete mode 100644 include/cru/common/HandlerRegistry.h delete mode 100644 include/cru/common/PreConfig.h delete mode 100644 include/cru/common/PropertyTree.h delete mode 100644 include/cru/common/Range.h delete mode 100644 include/cru/common/SelfResolvable.h delete mode 100644 include/cru/common/String.h delete mode 100644 include/cru/common/StringToNumberConverter.h delete mode 100644 include/cru/common/StringUtil.h delete mode 100644 include/cru/common/SubProcess.h delete mode 100644 include/cru/common/concurrent/ConcurrentQueue.h delete mode 100644 include/cru/common/io/AutoReadStream.h delete mode 100644 include/cru/common/io/BufferStream.h delete mode 100644 include/cru/common/io/CFileStream.h delete mode 100644 include/cru/common/io/MemoryStream.h delete mode 100644 include/cru/common/io/OpenFileFlag.h delete mode 100644 include/cru/common/io/ProxyStream.h delete mode 100644 include/cru/common/io/Resource.h delete mode 100644 include/cru/common/io/Stream.h delete mode 100644 include/cru/common/log/Logger.h delete mode 100644 include/cru/common/log/StdioLogTarget.h delete mode 100644 include/cru/common/platform/Exception.h delete mode 100644 include/cru/common/platform/osx/Convert.h delete mode 100644 include/cru/common/platform/osx/Exception.h delete mode 100644 include/cru/common/platform/unix/PosixSpawnSubProcess.h delete mode 100644 include/cru/common/platform/unix/UnixFileStream.h delete mode 100644 include/cru/common/platform/unix/UnixPipe.h delete mode 100644 include/cru/common/platform/web/WebException.h delete mode 100644 include/cru/common/platform/win/ComAutoInit.h delete mode 100644 include/cru/common/platform/win/DebugLogTarget.h delete mode 100644 include/cru/common/platform/win/Exception.h delete mode 100644 include/cru/common/platform/win/StreamConvert.h delete mode 100644 include/cru/common/platform/win/Win32FileStream.h delete mode 100644 include/cru/common/platform/win/WinPreConfig.h create mode 100644 src/base/Base.cpp create mode 100644 src/base/Buffer.cpp create mode 100644 src/base/CMakeLists.txt create mode 100644 src/base/Exception.cpp create mode 100644 src/base/Format.cpp create mode 100644 src/base/PropertyTree.cpp create mode 100644 src/base/String.cpp create mode 100644 src/base/StringToNumberConverter.cpp create mode 100644 src/base/StringUtil.cpp create mode 100644 src/base/SubProcess.cpp create mode 100644 src/base/io/AutoReadStream.cpp create mode 100644 src/base/io/BufferStream.cpp create mode 100644 src/base/io/CFileStream.cpp create mode 100644 src/base/io/MemoryStream.cpp create mode 100644 src/base/io/OpenFileFlag.cpp create mode 100644 src/base/io/ProxyStream.cpp create mode 100644 src/base/io/Resource.cpp create mode 100644 src/base/io/Stream.cpp create mode 100644 src/base/log/Logger.cpp create mode 100644 src/base/log/StdioLogTarget.cpp create mode 100644 src/base/platform/Exception.cpp create mode 100644 src/base/platform/osx/Convert.cpp create mode 100644 src/base/platform/osx/Exception.cpp create mode 100644 src/base/platform/unix/PosixSpawnSubProcess.cpp create mode 100644 src/base/platform/unix/UnixFileStream.cpp create mode 100644 src/base/platform/unix/UnixPipe.cpp create mode 100644 src/base/platform/web/WebException.cpp create mode 100644 src/base/platform/win/BridgeComStream.cpp create mode 100644 src/base/platform/win/BrigdeComStream.h create mode 100644 src/base/platform/win/ComAutoInit.cpp create mode 100644 src/base/platform/win/DebugLogTarget.cpp create mode 100644 src/base/platform/win/Exception.cpp create mode 100644 src/base/platform/win/StreamConvert.cpp create mode 100644 src/base/platform/win/Win32FileStream.cpp create mode 100644 src/base/platform/win/Win32FileStreamPrivate.h delete mode 100644 src/common/Base.cpp delete mode 100644 src/common/Buffer.cpp delete mode 100644 src/common/CMakeLists.txt delete mode 100644 src/common/Exception.cpp delete mode 100644 src/common/Format.cpp delete mode 100644 src/common/PropertyTree.cpp delete mode 100644 src/common/String.cpp delete mode 100644 src/common/StringToNumberConverter.cpp delete mode 100644 src/common/StringUtil.cpp delete mode 100644 src/common/SubProcess.cpp delete mode 100644 src/common/io/AutoReadStream.cpp delete mode 100644 src/common/io/BufferStream.cpp delete mode 100644 src/common/io/CFileStream.cpp delete mode 100644 src/common/io/MemoryStream.cpp delete mode 100644 src/common/io/OpenFileFlag.cpp delete mode 100644 src/common/io/ProxyStream.cpp delete mode 100644 src/common/io/Resource.cpp delete mode 100644 src/common/io/Stream.cpp delete mode 100644 src/common/log/Logger.cpp delete mode 100644 src/common/log/StdioLogTarget.cpp delete mode 100644 src/common/platform/Exception.cpp delete mode 100644 src/common/platform/osx/Convert.cpp delete mode 100644 src/common/platform/osx/Exception.cpp delete mode 100644 src/common/platform/unix/PosixSpawnSubProcess.cpp delete mode 100644 src/common/platform/unix/UnixFileStream.cpp delete mode 100644 src/common/platform/unix/UnixPipe.cpp delete mode 100644 src/common/platform/web/WebException.cpp delete mode 100644 src/common/platform/win/BridgeComStream.cpp delete mode 100644 src/common/platform/win/BrigdeComStream.h delete mode 100644 src/common/platform/win/ComAutoInit.cpp delete mode 100644 src/common/platform/win/DebugLogTarget.cpp delete mode 100644 src/common/platform/win/Exception.cpp delete mode 100644 src/common/platform/win/StreamConvert.cpp delete mode 100644 src/common/platform/win/Win32FileStream.cpp delete mode 100644 src/common/platform/win/Win32FileStreamPrivate.h diff --git a/demos/Graphics/DrawCircle/DrawCircle.cpp b/demos/Graphics/DrawCircle/DrawCircle.cpp index aa73d44c..a28bc4e4 100644 --- a/demos/Graphics/DrawCircle/DrawCircle.cpp +++ b/demos/Graphics/DrawCircle/DrawCircle.cpp @@ -1,4 +1,4 @@ -#include "cru/common/io/CFileStream.h" +#include "cru/base/io/CFileStream.h" #include "cru/platform/Color.h" #include "cru/platform/graphics/Factory.h" #include "cru/platform/graphics/ImageFactory.h" diff --git a/include/cru/base/Base.h b/include/cru/base/Base.h new file mode 100644 index 00000000..8a6a7634 --- /dev/null +++ b/include/cru/base/Base.h @@ -0,0 +1,112 @@ +#pragma once +#include "PreConfig.h" // IWYU pragma: keep + +#include +#include +#include +#include + +#ifdef CRU_PLATFORM_WINDOWS +#ifdef CRU_BASE_EXPORT_API +#define CRU_BASE_API __declspec(dllexport) +#else +#define CRU_BASE_API __declspec(dllimport) +#endif +#else +#define CRU_BASE_API +#endif + +#define CRU_UNUSED(entity) static_cast(entity); + +#define CRU__CONCAT(a, b) a##b +#define CRU_MAKE_UNICODE_LITERAL(str) CRU__CONCAT(u, #str) + +#define CRU_DEFAULT_COPY(classname) \ + classname(const classname&) = default; \ + classname& operator=(const classname&) = default; + +#define CRU_DEFAULT_MOVE(classname) \ + classname(classname&&) = default; \ + classname& operator=(classname&&) = default; + +#define CRU_DELETE_COPY(classname) \ + classname(const classname&) = delete; \ + classname& operator=(const classname&) = delete; + +#define CRU_DELETE_MOVE(classname) \ + classname(classname&&) = delete; \ + classname& operator=(classname&&) = delete; + +#define CRU_DEFAULT_DESTRUCTOR(classname) ~classname() = default; + +#define CRU_DEFAULT_CONSTRUCTOR_DESTRUCTOR(classname) \ + classname() = default; \ + ~classname() = default; + +#define CRU_DEFINE_COMPARE_OPERATORS(classname) \ + inline bool operator==(const classname& left, const classname& right) { \ + return left.Compare(right) == 0; \ + } \ + \ + inline bool operator!=(const classname& left, const classname& right) { \ + return left.Compare(right) != 0; \ + } \ + \ + inline bool operator<(const classname& left, const classname& right) { \ + return left.Compare(right) < 0; \ + } \ + \ + inline bool operator<=(const classname& left, const classname& right) { \ + return left.Compare(right) <= 0; \ + } \ + \ + inline bool operator>(const classname& left, const classname& right) { \ + return left.Compare(right) > 0; \ + } \ + \ + inline bool operator>=(const classname& left, const classname& right) { \ + return left.Compare(right) >= 0; \ + } + +namespace cru { +class CRU_BASE_API Object { + public: + Object() = default; + CRU_DEFAULT_COPY(Object) + CRU_DEFAULT_MOVE(Object) + virtual ~Object() = default; +}; + +struct CRU_BASE_API Interface { + Interface() = default; + CRU_DELETE_COPY(Interface) + CRU_DELETE_MOVE(Interface) + virtual ~Interface() = default; +}; + +[[noreturn]] void CRU_BASE_API UnreachableCode(); + +using Index = std::ptrdiff_t; + +inline void Expects(bool condition) { assert(condition); } +inline void Ensures(bool condition) { assert(condition); } +template +inline void Expects(const std::shared_ptr& ptr) { + assert(ptr != nullptr); +} +template +inline void Ensures(const std::shared_ptr& ptr) { + assert(ptr != nullptr); +} + +// https://www.boost.org/doc/libs/1_54_0/doc/html/hash/reference.html#boost.hash_combine +template +inline void hash_combine(std::size_t& s, const T& v) { + std::hash h; + s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2); +} + +#define CRU_DEFINE_CLASS_LOG_TAG(tag) \ + private: \ + constexpr static const char16_t* kLogTag = tag; +} // namespace cru diff --git a/include/cru/base/Bitmask.h b/include/cru/base/Bitmask.h new file mode 100644 index 00000000..9b6b8957 --- /dev/null +++ b/include/cru/base/Bitmask.h @@ -0,0 +1,55 @@ +#pragma once + +#include + +namespace cru { +template +struct Bitmask final { + using Underlying = TUnderlying; + + constexpr Bitmask() : value(0) {} + constexpr explicit Bitmask(TUnderlying value) : value(value) {} + + static constexpr Bitmask FromOffset(int offset) { + return Bitmask(static_cast(1u << offset)); + } + + constexpr bool Has(Bitmask rhs) const { return (value & rhs.value) != 0; } + + Bitmask operator|(Bitmask rhs) const { return Bitmask(value | rhs.value); } + Bitmask operator&(Bitmask rhs) const { return Bitmask(value & rhs.value); } + Bitmask operator^(Bitmask rhs) const { return Bitmask(value ^ rhs.value); } + Bitmask operator~() const { return Bitmask(~value); } + Bitmask& operator|=(Bitmask rhs) { + value |= rhs.value; + return *this; + } + Bitmask& operator&=(Bitmask rhs) { + value &= rhs.value; + return *this; + } + Bitmask& operator^=(Bitmask rhs) { + value ^= rhs.value; + return *this; + } + + bool operator==(Bitmask rhs) const { return this->value == rhs.value; } + bool operator!=(Bitmask rhs) const { return this->value != rhs.value; } + + explicit operator TUnderlying() const { return value; } + operator bool() const { return value != 0; } + + TUnderlying value; +}; +} // namespace cru + +namespace std { +template +struct hash> { + using Bitmask = cru::Bitmask; + + std::size_t operator()(Bitmask bitmask) const { + return std::hash{}(bitmask.value); + } +}; +} // namespace std diff --git a/include/cru/base/Buffer.h b/include/cru/base/Buffer.h new file mode 100644 index 00000000..bc2e2a26 --- /dev/null +++ b/include/cru/base/Buffer.h @@ -0,0 +1,161 @@ +#pragma once + +#include "Base.h" + +namespace cru { +class Buffer final { + friend void swap(Buffer& left, Buffer& right) noexcept; + + public: + Buffer(); + explicit Buffer(Index size); + + Buffer(const Buffer& other); + Buffer(Buffer&& other) noexcept; + + Buffer& operator=(const Buffer& other); + Buffer& operator=(Buffer&& other) noexcept; + + ~Buffer(); + + public: + Index GetBufferSize() const { return size_; } + Index GetUsedSize() const { return used_end_ - used_begin_; } + bool IsNull() const { return ptr_ == nullptr; } + bool IsUsedReachEnd() const { return used_end_ == size_; } + + Index GetFrontFree() const { return used_begin_; } + Index GetBackFree() const { return size_ - used_end_; } + + Index GetUsedBegin() const { return used_begin_; } + Index GetUsedEnd() const { return used_end_; } + + std::byte* GetPtr() { return GetPtrAt(0); } + const std::byte* GetPtr() const { return GetPtrAt(0); } + + std::byte* GetPtrAt(Index index) { return ptr_ + index; } + const std::byte* GetPtrAt(Index index) const { return ptr_ + index; } + + std::byte& GetRefAt(Index index) { return *GetPtrAt(index); } + const std::byte& GetRefAt(Index index) const { return *GetPtrAt(index); } + + std::byte* GetUsedBeginPtr() { return GetPtrAt(GetUsedBegin()); } + const std::byte* GetUsedBeginPtr() const { return GetPtrAt(GetUsedBegin()); } + std::byte* GetUsedEndPtr() { return GetPtrAt(GetUsedEnd()); } + const std::byte* GetUsedEndPtr() const { return GetPtrAt(GetUsedEnd()); } + + std::byte GetByteAt(Index index) const { return ptr_[index]; } + void SetByteAt(Index index, std::byte value) { ptr_[index] = value; } + + void AssignBytes(std::byte* src, Index src_size, bool use_memmove = false) { + return AssignBytes(0, src, 0, src_size, use_memmove); + } + void AssignBytes(Index dst_offset, std::byte* src, Index src_size, + bool use_memmove = false) { + return AssignBytes(dst_offset, src, 0, src_size, use_memmove); + } + void AssignBytes(Index dst_offset, std::byte* src, Index src_offset, + Index src_size, bool use_memmove = false); + + /** + * @brief Change the size of the buffer. + * + * Unless new size is the same as current size, the buffer is always released + * and a new one is allocated. If preserve_used is true, the used size and old + * data is copied to the new buffer. If new size is smaller than old used + * size, then exceeded data will be lost. + */ + void ResizeBuffer(Index new_size, bool preserve_used); + + /** + * @brief Append data to the front of used bytes and increase used size. + * @return The actual size of data saved. + * + * If there is no enough space left for new data, the rest space will be + * written and the size of it will be returned, leaving exceeded data not + * saved. + */ + Index PushFront(const std::byte* other, Index other_size, + bool use_memmove = false); + + bool PushBack(std::byte b); + + /** + * @brief Append data to the back of used bytes and increase used size. + * @return The actual size of data saved. + * + * If there is no enough space left for new data, the rest space will be + * written and the size of it will be returned, leaving exceeded data not + * saved. + */ + Index PushBack(const std::byte* other, Index other_size, + bool use_memmove = false); + + void PushBackCount(Index count); + + /** + * @brief Move forward the used-begin ptr. + * @return The actual size moved forward. + * + * If given size is bigger than current used size, the used size will be + * returned and set to 0. + */ + Index PopFront(Index size); + + /** + * @brief Pop front data of used bytes into another buffer. + * @return The actual size popped. + * + * If given size is bigger than current used size, then only current used size + * of bytes will be popped. If given size is smaller than current used size, + * then only given size of bytes will be popped. + */ + Index PopFront(std::byte* buffer, Index size, bool use_memmove = false); + + /** + * @brief Move backward the used-end ptr. + * @return The actual size moved backward. + * + * If given size is bigger than current used size, the used size will be + * returned and set to 0. + */ + Index PopEnd(Index size); + + /** + * @brief Pop back data of used bytes into another buffer. + * @return The actual size popped. + * + * If given size is bigger than current used size, then only current used size + * of bytes will be popped. If given size is smaller than current used size, + * then only given size of bytes will be popped. + */ + Index PopEnd(std::byte* buffer, Index size, bool use_memmove = false); + + operator std::byte*() { return GetPtr(); } + operator const std::byte*() const { return GetPtr(); } + + /** + * @brief Detach internal buffer and return it. + * @param size If not null, size of the buffer is written to it. + * @return The buffer pointer. May be nullptr. + * + * After detach, you are responsible to delete[] it. + */ + std::byte* Detach(Index* size = nullptr); + + private: + void Copy_(const Buffer& other); + void Move_(Buffer&& other) noexcept; + void Delete_() noexcept; + + void AssertValid(); + + private: + std::byte* ptr_; + Index size_; + Index used_begin_; + Index used_end_; +}; + +void swap(Buffer& left, Buffer& right) noexcept; +} // namespace cru diff --git a/include/cru/base/ClonablePtr.h b/include/cru/base/ClonablePtr.h new file mode 100644 index 00000000..a2a88758 --- /dev/null +++ b/include/cru/base/ClonablePtr.h @@ -0,0 +1,216 @@ +#pragma once + +#include +#include +#include +#include + +namespace cru { +template +class ClonablePtr { + template + friend class ClonablePtr; + + public: + using element_type = typename std::unique_ptr::element_type; + using pointer = typename std::unique_ptr::pointer; + + ClonablePtr() = default; + ClonablePtr(std::nullptr_t) noexcept : ptr_(nullptr) {} + explicit ClonablePtr(pointer p) noexcept : ptr_(p) {} + ClonablePtr(std::unique_ptr&& p) noexcept + : ptr_(std::move(p)) {} + template ::pointer, pointer>, + int> = 0> + ClonablePtr(std::unique_ptr&& p) : ptr_(std::move(p)) {} + ClonablePtr(const ClonablePtr& other) : ptr_(other.ptr_->Clone()) {} + ClonablePtr(ClonablePtr&& other) = default; + template ::pointer, pointer>, + int> = 0> + ClonablePtr(const ClonablePtr& other) : ptr_(other.ptr_->Clone()) {} + template ::pointer, pointer>, + int> = 0> + ClonablePtr(ClonablePtr&& other) noexcept : ptr_(std::move(other.ptr_)) {} + ClonablePtr& operator=(std::nullptr_t) noexcept { + ptr_ = nullptr; + return *this; + } + ClonablePtr& operator=(std::unique_ptr&& other) noexcept { + ptr_ = std::move(other); + return *this; + } + template ::pointer, pointer>, + int> = 0> + ClonablePtr& operator=(std::unique_ptr&& p) noexcept { + ptr_ = std::move(p); + return *this; + } + ClonablePtr& operator=(const ClonablePtr& other) { + if (this != &other) { + ptr_ = std::unique_ptr(other.ptr_->Clone()); + } + return *this; + } + ClonablePtr& operator=(ClonablePtr&& other) = default; + template ::pointer, pointer>, + int> = 0> + ClonablePtr& operator=(const ClonablePtr& other) noexcept { + if (this != &other) { + ptr_ = std::unique_ptr(other.ptr_->Clone()); + } + return *this; + } + template ::pointer, pointer>, + int> = 0> + ClonablePtr& operator=(ClonablePtr&& other) noexcept { + ptr_ = std::move(other.ptr_); + } + + ~ClonablePtr() = default; + + public: + pointer release() noexcept { return ptr_.release(); } + void reset(pointer p = pointer()) noexcept { ptr_.reset(p); } + void swap(ClonablePtr& other) noexcept { ptr_.swap(other.ptr_); } + + public: + pointer get() const noexcept { return ptr_.get(); } + + operator bool() const noexcept { return ptr_ != nullptr; } + + element_type& operator*() const noexcept { return *ptr_; } + pointer operator->() const noexcept { return ptr_.get(); } + + int Compare(const ClonablePtr& other) const noexcept { + if (ptr_ == other.ptr_) { + return 0; + } else if (ptr_ < other.ptr_) { + return -1; + } else { + return 1; + } + } + + int Compare(nullptr_t) const noexcept { return ptr_ ? 1 : 0; } + + private: + std::unique_ptr ptr_; +}; + +template +void swap(ClonablePtr& left, ClonablePtr& right) noexcept { + left.swap(right); +} + +template +bool operator==(const ClonablePtr& left, const ClonablePtr& right) { + return left.Compare(right) == 0; +} + +template +bool operator!=(const ClonablePtr& left, const ClonablePtr& right) { + return left.Compare(right) != 0; +} + +template +bool operator<(const ClonablePtr& left, const ClonablePtr& right) { + return left.Compare(right) < 0; +} + +template +bool operator<=(const ClonablePtr& left, const ClonablePtr& right) { + return left.Compare(right) <= 0; +} + +template +bool operator>(const ClonablePtr& left, const ClonablePtr& right) { + return left.Compare(right) > 0; +} + +template +bool operator>=(const ClonablePtr& left, const ClonablePtr& right) { + return left.Compare(right) >= 0; +} + +template +bool operator==(const ClonablePtr& left, std::nullptr_t) { + return left.Compare(nullptr) == 0; +} + +template +bool operator!=(const ClonablePtr& left, std::nullptr_t) { + return left.Compare(nullptr) != 0; +} + +template +bool operator<(const ClonablePtr& left, std::nullptr_t) { + return left.Compare(nullptr) < 0; +} + +template +bool operator<=(const ClonablePtr& left, std::nullptr_t) { + return left.Compare(nullptr) <= 0; +} + +template +bool operator>(const ClonablePtr& left, std::nullptr_t) { + return left.Compare(nullptr) > 0; +} + +template +bool operator>=(const ClonablePtr& left, std::nullptr_t) { + return left.Compare(nullptr) >= 0; +} + +template +bool operator==(std::nullptr_t, const ClonablePtr& right) { + return right.Compare(nullptr) == 0; +} + +template +bool operator!=(std::nullptr_t, const ClonablePtr& right) { + return right.Compare(nullptr) != 0; +} + +template +bool operator<(std::nullptr_t, const ClonablePtr& right) { + return right.Compare(nullptr) > 0; +} + +template +bool operator<=(std::nullptr_t, const ClonablePtr& right) { + return right.Compare(nullptr) >= 0; +} + +template +bool operator>(std::nullptr_t, const ClonablePtr& right) { + return right.Compare(nullptr) < 0; +} + +template +bool operator>=(std::nullptr_t, const ClonablePtr& right) { + return right.Compare(nullptr) <= 0; +} + +} // namespace cru + +namespace std { +template +struct hash> { + std::size_t operator()(const cru::ClonablePtr& p) const { + return std::hash::pointer>(p.get()); + } +}; +} // namespace std diff --git a/include/cru/base/Event.h b/include/cru/base/Event.h new file mode 100644 index 00000000..18d2c570 --- /dev/null +++ b/include/cru/base/Event.h @@ -0,0 +1,281 @@ +#pragma once +#include "Base.h" + +#include "SelfResolvable.h" + +#include +#include +#include +#include +#include +#include + +namespace cru { +class EventRevoker; + +namespace details { +template +inline constexpr bool always_false_v = false; + +// Base class of all Event. +// It erases event args types and provides a +// unified form to create event revoker and +// revoke(remove) handler. +class EventBase : public SelfResolvable { + friend EventRevoker; + + protected: + using EventHandlerToken = long; + + EventBase() {} + CRU_DELETE_COPY(EventBase) + CRU_DEFAULT_MOVE(EventBase) + virtual ~EventBase() = default; + + // Remove the handler with the given token. If the token + // corresponds to no handler (which might have be revoked + // before), then nothing will be done. + virtual void RemoveHandler(EventHandlerToken token) = 0; + + // Create a revoker with the given token. + inline EventRevoker CreateRevoker(EventHandlerToken token); +}; +} // namespace details + +// A non-copyable and movable event revoker. +// Call function call operator to revoke the handler. +class EventRevoker { + friend details::EventBase; + + private: + EventRevoker(ObjectResolver&& resolver, + details::EventBase::EventHandlerToken token) + : resolver_(std::move(resolver)), token_(token) {} + + public: + EventRevoker(const EventRevoker& other) = default; + EventRevoker(EventRevoker&& other) = default; + EventRevoker& operator=(const EventRevoker& other) = default; + EventRevoker& operator=(EventRevoker&& other) = default; + ~EventRevoker() = default; + + // Revoke the registered handler. If the event has already + // been destroyed, then nothing will be done. If one of the + // copies calls this, then other copies's calls will have no + // effect. (They have the same token.) + void operator()() const { + if (const auto event = resolver_.Resolve()) { + event->RemoveHandler(token_); + } + } + + private: + ObjectResolver resolver_; + details::EventBase::EventHandlerToken token_; +}; + +inline EventRevoker details::EventBase::CreateRevoker(EventHandlerToken token) { + return EventRevoker(CreateResolver(), token); +} + +// int -> int +// Point -> const Point& +// int& -> int& +template +using DeducedEventArgs = std::conditional_t< + std::is_lvalue_reference_v, TRaw, + std::conditional_t, TRaw, const TRaw&>>; + +struct IBaseEvent { + protected: + IBaseEvent() = default; + CRU_DELETE_COPY(IBaseEvent) + CRU_DEFAULT_MOVE(IBaseEvent) + ~IBaseEvent() = default; // Note that user can't destroy a Event via IEvent. + // So destructor should be protected. + + using SpyOnlyHandler = std::function; + + public: + virtual EventRevoker AddSpyOnlyHandler(SpyOnlyHandler handler) = 0; +}; + +// Provides an interface of event. +// IEvent only allow to add handler but not to raise the event. You may +// want to create an Event object and expose IEvent only so users won't +// be able to emit the event. +template +struct IEvent : virtual IBaseEvent { + public: + using EventArgs = DeducedEventArgs; + using EventHandler = std::function; + using ShortCircuitHandler = std::function; + + protected: + IEvent() = default; + CRU_DELETE_COPY(IEvent) + CRU_DEFAULT_MOVE(IEvent) + ~IEvent() = default; // Note that user can't destroy a Event via IEvent. So + // destructor should be protected. + + public: + virtual EventRevoker AddHandler(EventHandler handler) = 0; + virtual EventRevoker AddShortCircuitHandler(ShortCircuitHandler handler) = 0; + virtual EventRevoker PrependShortCircuitHandler( + ShortCircuitHandler handler) = 0; +}; + +// A non-copyable non-movable Event class. +// It stores a list of event handlers. +template +class Event : public details::EventBase, public IEvent { + using typename IEvent::EventArgs; + + using typename IBaseEvent::SpyOnlyHandler; + using typename IEvent::EventHandler; + using typename IEvent::ShortCircuitHandler; + + private: + struct HandlerData { + HandlerData(EventHandlerToken token, ShortCircuitHandler handler) + : token(token), handler(std::move(handler)) {} + EventHandlerToken token; + ShortCircuitHandler handler; + }; + + public: + Event() = default; + CRU_DELETE_COPY(Event) + CRU_DEFAULT_MOVE(Event) + ~Event() = default; + + EventRevoker AddSpyOnlyHandler(SpyOnlyHandler handler) override { + return AddShortCircuitHandler([handler = std::move(handler)](EventArgs) { + handler(); + return false; + }); + } + + EventRevoker AddHandler(EventHandler handler) override { + return AddShortCircuitHandler( + [handler = std::move(handler)](EventArgs args) { + handler(args); + return false; + }); + } + + // Handler return true to short circuit following handlers. + EventRevoker AddShortCircuitHandler(ShortCircuitHandler handler) override { + const auto token = current_token_++; + this->handler_data_list_.emplace_back(token, std::move(handler)); + return CreateRevoker(token); + } + + // Handler return true to short circuit following handlers. + EventRevoker PrependShortCircuitHandler( + ShortCircuitHandler handler) override { + const auto token = current_token_++; + this->handler_data_list_.emplace(this->handler_data_list_.cbegin(), token, + std::move(handler)); + return CreateRevoker(token); + } + + // This method will make a copy of all handlers. Because user might delete a + // handler in a handler, which may lead to seg fault as the handler is + // deleted while being executed. Thanks to this behavior, all handlers will + // be taken a snapshot when Raise is called, so even if you delete a handler + // during this period, all handlers in the snapshot will be executed. + void Raise(EventArgs args) { + std::vector handlers; + handlers.reserve(this->handler_data_list_.size()); + for (const auto& data : this->handler_data_list_) { + handlers.push_back(data.handler); + } + for (const auto& handler : handlers) { + auto short_circuit = handler(args); + if (short_circuit) return; + } + } + + protected: + void RemoveHandler(EventHandlerToken token) override { + const auto find_result = std::find_if( + this->handler_data_list_.cbegin(), this->handler_data_list_.cend(), + [token](const HandlerData& data) { return data.token == token; }); + if (find_result != this->handler_data_list_.cend()) { + this->handler_data_list_.erase(find_result); + } + } + + private: + std::vector handler_data_list_; + EventHandlerToken current_token_ = 0; +}; + +namespace details { +struct EventRevokerDestroyer { + void operator()(EventRevoker* p) { + (*p)(); + delete p; + } +}; +} // namespace details + +// A guard class for event revoker. Automatically revoke it when destroyed. +class EventRevokerGuard { + public: + EventRevokerGuard() = default; + explicit EventRevokerGuard(EventRevoker&& revoker) + : revoker_(new EventRevoker(std::move(revoker))) {} + EventRevokerGuard(const EventRevokerGuard& other) = delete; + EventRevokerGuard(EventRevokerGuard&& other) = default; + EventRevokerGuard& operator=(const EventRevokerGuard& other) = delete; + EventRevokerGuard& operator=(EventRevokerGuard&& other) = default; + ~EventRevokerGuard() = default; + + EventRevoker Get() { + // revoker is only null when this is moved + // you shouldn't use a moved instance + assert(revoker_); + return *revoker_; + } + + EventRevoker Release() { return std::move(*revoker_.release()); } + + void Reset() { revoker_.reset(); } + + void Reset(EventRevoker&& revoker) { + revoker_.reset(new EventRevoker(std::move(revoker))); + } + + private: + std::unique_ptr revoker_; +}; + +class EventRevokerListGuard { + public: + EventRevokerListGuard() = default; + EventRevokerListGuard(const EventRevokerListGuard& other) = delete; + EventRevokerListGuard(EventRevokerListGuard&& other) = default; + EventRevokerListGuard& operator=(const EventRevokerListGuard& other) = delete; + EventRevokerListGuard& operator=(EventRevokerListGuard&& other) = default; + ~EventRevokerListGuard() = default; + + public: + void Add(EventRevoker&& revoker) { + event_revoker_guard_list_.push_back(EventRevokerGuard(std::move(revoker))); + } + + EventRevokerListGuard& operator+=(EventRevoker&& revoker) { + this->Add(std::move(revoker)); + return *this; + } + + void Clear() { event_revoker_guard_list_.clear(); } + + bool IsEmpty() const { return event_revoker_guard_list_.empty(); } + + private: + std::vector event_revoker_guard_list_; +}; +} // namespace cru diff --git a/include/cru/base/Event2.h b/include/cru/base/Event2.h new file mode 100644 index 00000000..891b314f --- /dev/null +++ b/include/cru/base/Event2.h @@ -0,0 +1,200 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace cru { +class Event2Base { + public: + virtual ~Event2Base() = default; + + virtual void RevokeHandler(int token_value) = 0; +}; + +template +class EventContext { + public: + EventContext() : argument_(), result_() {} + explicit EventContext(TArgument argument) + : argument_(std::move(argument)), result_() {} + EventContext(TArgument argument, TResult result) + : argument_(std::move(argument)), result_(std::move(result)) {} + + TArgument& GetArgument() { return argument_; } + const TArgument& GetArgument() const { return argument_; } + + TResult& GetResult() { return result_; } + const TResult& GetResult() const { return result_; } + void SetResult(const TResult& result) { result_ = result; } + void SetResult(TResult&& result) { result_ = std::move(result); } + TResult TakeResult() { return std::move(result_); } + + bool GetStopHandling() const { return stop_handling_; } + void SetStopHandling(bool stop = true) { stop_handling_ = stop; } + + private: + TArgument argument_; + TResult result_; + bool stop_handling_ = false; +}; + +template +class Event2; + +template +constexpr bool is_event2_v = false; + +template +constexpr bool is_event2_v> = true; + +class EventHandlerToken { + public: + EventHandlerToken(ObjectResolver event_resolver, int token_value) + : event_resolver_(std::move(event_resolver)), token_value_(token_value) {} + + ObjectResolver GetEventResolver() const { + return event_resolver_; + } + int GetTokenValue() const { return token_value_; } + inline void RevokeHandler() const; + + private: + ObjectResolver event_resolver_; + int token_value_; +}; + +namespace details { +struct Event2BehaviorFlagTag {}; +} // namespace details +using Event2BehaviorFlag = Bitmask; + +struct Event2BehaviorFlags { + /** + * @brief Make a copy of handler list before invoking handlers. So the event + * object or its owner can be destroyed during running handlers. + */ + static constexpr Event2BehaviorFlag CopyHandlers = + Event2BehaviorFlag::FromOffset(1); +}; + +template +class Event2 : public Event2Base, + public SelfResolvable> { + public: + using HandlerToken = EventHandlerToken; + using Context = EventContext; + using Handler = std::function; + using SpyOnlyHandler = std::function; + + template + static std::enable_if_t, Handler> WrapAsHandler( + TFunc&& handler) { + return Handler([h = std::forward(handler)](Context*) { h(); }); + } + + template + static std::enable_if_t, Handler> + WrapAsHandler(TFunc&& handler) { + return Handler(std::forward(handler)); + } + + private: + struct HandlerData { + int token_value; + Handler handler; + }; + + public: + explicit Event2(Event2BehaviorFlag flags = {}) : flags_(flags) {} + Event2(const Event2&) = delete; + Event2(Event2&&) = delete; + Event2& operator=(const Event2&) = delete; + Event2& operator=(Event2&&) = delete; + ~Event2() override = default; + + public: + template + HandlerToken AddHandler(TFunc&& handler) { + auto token = this->current_token_value_++; + auto real_handler = WrapAsHandler(std::forward(handler)); + HandlerData handler_data{token, std::move(real_handler)}; + this->handlers_.push_back(std::move(handler_data)); + return HandlerToken(this->CreateResolver(), token); + } + + void RevokeHandler(int token_value) override { + auto iter = this->handlers_.cbegin(); + auto end = this->handlers_.cend(); + for (; iter != end; ++iter) { + if (iter->token_value == token_value) { + this->handlers_.erase(iter); + break; + } + } + } + + void RevokeHandler(const HandlerToken& token) { + return RevokeHandler(token.GetTokenValue()); + } + + TResult Raise() { + Context context; + RunInContext(&context); + return context.TakeResult(); + } + + TResult Raise(TArgument argument) { + Context context(std::move(argument)); + RunInContext(&context); + return context.TakeResult(); + } + + TResult Raise(TArgument argument, TResult result) { + Context context(std::move(argument), std::move(result)); + RunInContext(&context); + return context.TakeResult(); + } + + private: + void RunInContext(Context* context) { + if (this->flags_ & Event2BehaviorFlags::CopyHandlers) { + std::vector handlers_copy; + for (const auto& handler : this->handlers_) { + handlers_copy.push_back(handler.handler); + } + for (const auto& handler : handlers_copy) { + if (context->GetStopHandling()) { + break; + } + handler(context); + } + } else { + for (const auto& handler : this->handlers_) { + if (context->GetStopHandling()) { + break; + } + handler.handler(context); + } + } + } + + private: + int current_token_value_ = 1; + std::vector handlers_; + Event2BehaviorFlag flags_; +}; + +inline void EventHandlerToken::RevokeHandler() const { + auto event = this->event_resolver_.Resolve(); + if (event) { + event->RevokeHandler(this->token_value_); + } +} +} // namespace cru diff --git a/include/cru/base/Exception.h b/include/cru/base/Exception.h new file mode 100644 index 00000000..609fd2c9 --- /dev/null +++ b/include/cru/base/Exception.h @@ -0,0 +1,60 @@ +#pragma once +#include "String.h" + +#include +#include + +namespace cru { +#ifdef _MSC_VER +#pragma warning(disable : 4275) +#endif +class CRU_BASE_API Exception : public std::exception { + public: + explicit Exception(String message = {}, + std::unique_ptr inner = nullptr); + + ~Exception() override; + + public: + String GetMessage() const { return message_; } + + std::exception* GetInner() const noexcept { return inner_.get(); } + + const char* what() const noexcept override; + + protected: + void SetMessage(String message) { message_ = std::move(message); } + + void AppendMessage(StringView additional_message); + void AppendMessage(std::optional additional_message); + + private: + String message_; + mutable std::string utf8_message_; + std::unique_ptr inner_; +}; + +class CRU_BASE_API TextEncodeException : public Exception { + public: + using Exception::Exception; +}; + +class ErrnoException : public Exception { + public: + /** + * @brief will retrieve errno automatically. + */ + explicit ErrnoException(String message = {}); + ErrnoException(String message, int errno_code); + + CRU_DELETE_COPY(ErrnoException) + CRU_DELETE_MOVE(ErrnoException) + + ~ErrnoException() override = default; + + int GetErrnoCode() const { return errno_code_; } + + private: + int errno_code_; +}; +} // namespace cru diff --git a/include/cru/base/Format.h b/include/cru/base/Format.h new file mode 100644 index 00000000..d5c5ed99 --- /dev/null +++ b/include/cru/base/Format.h @@ -0,0 +1,154 @@ +#pragma once + +#include "Exception.h" +#include "String.h" + +#include +#include +#include +#include + +namespace cru { +inline String ToString(bool value) { + return value ? String(u"true") : String(u"false"); +} + +template +inline constexpr std::nullptr_t kPrintfFormatSpecifierOfType = nullptr; + +#define CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(type, specifier) \ + template <> \ + inline constexpr const char* kPrintfFormatSpecifierOfType = specifier; + +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed char, "%c") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned char, "%c") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed short, "%hd") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned short, "%hu") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed int, "%d") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned int, "%u") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed long, "%ld") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned long, "%lu") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed long long, "%lld") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned long long, "%llu") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(float, "%f") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(double, "%f") + +#undef CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE + +template +std::enable_if_t< + !std::is_null_pointer_v)>, String> +ToString(T value) { + auto size = std::snprintf(nullptr, 0, kPrintfFormatSpecifierOfType, value); + assert(size > 0); + std::vector buffer(size + 1); + size = std::snprintf(buffer.data(), size + 1, kPrintfFormatSpecifierOfType, + value); + assert(size > 0); + return String::FromUtf8(buffer.data(), size); +} + +template +String ToString(const T& value, StringView option) { + CRU_UNUSED(option) + return ToString(value); +} + +inline String ToString(String value) { return value; } + +namespace details { +enum class FormatTokenType { PlaceHolder, Text }; +enum class FormatPlaceHolderType { None, Positioned, Named }; + +struct FormatToken { + static FormatToken Text() { + return FormatToken{FormatTokenType::Text, {}, {}, 0, {}, {}}; + } + + static FormatToken NonePlaceHolder(String option) { + return FormatToken(FormatTokenType::PlaceHolder, {}, + FormatPlaceHolderType::None, 0, {}, std::move(option)); + } + + static FormatToken PositionedPlaceHolder(int position, String option) { + return FormatToken(FormatTokenType::PlaceHolder, {}, + FormatPlaceHolderType::Positioned, position, {}, + std::move(option)); + } + + static FormatToken NamedPlaceHolder(String name, String option) { + return FormatToken(FormatTokenType::PlaceHolder, {}, + FormatPlaceHolderType::Named, 0, std::move(name), + std::move(option)); + } + + FormatToken(FormatTokenType type, String data, + FormatPlaceHolderType place_holder_type, + int place_holder_position, String place_holder_name, + String place_holder_option) + : type(type), + data(std::move(data)), + place_holder_type(place_holder_type), + place_holder_position(place_holder_position), + place_holder_name(std::move(place_holder_name)), + place_holder_option(std::move(place_holder_option)) {} + + CRU_DEFAULT_COPY(FormatToken) + CRU_DEFAULT_MOVE(FormatToken) + + CRU_DEFAULT_DESTRUCTOR(FormatToken) + + FormatTokenType type; + String data; + FormatPlaceHolderType place_holder_type; + int place_holder_position; + String place_holder_name; + String place_holder_option; +}; + +std::vector CRU_BASE_API ParseToFormatTokenList(StringView str); + +void CRU_BASE_API FormatAppendFromFormatTokenList( + String& current, const std::vector& format_token_list, + Index index); + +template +void FormatAppendFromFormatTokenList( + String& current, const std::vector& format_token_list, + Index index, TA&& args0, T&&... args) { + for (Index i = index; i < static_cast(format_token_list.size()); i++) { + const auto& token = format_token_list[i]; + if (token.type == FormatTokenType::PlaceHolder) { + if (token.place_holder_type == FormatPlaceHolderType::None) { + current += ToString(std::forward(args0), token.place_holder_option); + FormatAppendFromFormatTokenList(current, format_token_list, i + 1, + std::forward(args)...); + + return; + } else { + throw Exception( + u"Currently do not support positional or named place holder."); + } + } else { + current += token.data; + } + } +} +} // namespace details + +template +String Format(StringView format, T&&... args) { + String result; + + details::FormatAppendFromFormatTokenList( + result, details::ParseToFormatTokenList(format), 0, + std::forward(args)...); + + return result; +} + +template +String String::Format(T&&... args) const { + return cru::Format(*this, std::forward(args)...); +} +} // namespace cru diff --git a/include/cru/base/Guard.h b/include/cru/base/Guard.h new file mode 100644 index 00000000..5a9f9c5d --- /dev/null +++ b/include/cru/base/Guard.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace cru { +struct Guard { + using ExitFunc = std::function; + + Guard() = default; + explicit Guard(const ExitFunc& f) : on_exit(f) {} + explicit Guard(ExitFunc&& f) : on_exit(std::move(f)) {} + Guard(const Guard&) = delete; + Guard(Guard&&) = default; + Guard& operator=(const Guard&) = delete; + Guard& operator=(Guard&&) = default; + ~Guard() { + if (on_exit) { + on_exit(); + } + } + + void Drop() { on_exit = {}; } + + ExitFunc on_exit; +}; +} // namespace cru diff --git a/include/cru/base/HandlerRegistry.h b/include/cru/base/HandlerRegistry.h new file mode 100644 index 00000000..e405d1fd --- /dev/null +++ b/include/cru/base/HandlerRegistry.h @@ -0,0 +1,87 @@ +#pragma once +#include "Base.h" + +#include +#include +#include +#include + +namespace cru { + +template +class HandlerRegistryIterator { + public: + using RawIterator = + typename std::vector>>::const_iterator; + + explicit HandlerRegistryIterator(RawIterator raw) : raw_(std::move(raw)) {} + + CRU_DELETE_COPY(HandlerRegistryIterator) + CRU_DELETE_MOVE(HandlerRegistryIterator) + + ~HandlerRegistryIterator() = default; + + const std::function& operator*() const { return raw_->second; } + const std::function* operator->() const { return &raw_->second; } + + HandlerRegistryIterator& operator++() { + ++raw_; + return *this; + } + + HandlerRegistryIterator operator++(int) { + auto c = *this; + this->operator++(); + return c; + } + + bool operator==(const HandlerRegistryIterator& other) const { + return this->raw_ == other.raw_; + } + + bool operator!=(const HandlerRegistryIterator& other) const { + return !this->operator==(other); + } + + private: + RawIterator raw_; +}; + +template +class HandlerRegistry final { + public: + HandlerRegistry() = default; + CRU_DEFAULT_COPY(HandlerRegistry) + CRU_DEFAULT_MOVE(HandlerRegistry) + ~HandlerRegistry() = default; + + public: + int AddHandler(std::function handler) { + auto id = current_id_++; + handler_list_.push_back({id, std::move(handler)}); + return id; + } + + void RemoveHandler(int id) { + auto result = std::find_if(handler_list_.cbegin(), handler_list_.cend(), + [id](const std::pair>& d) { + return d.first == id; + }); + if (result != handler_list_.cend()) { + handler_list_.erase(result); + } + } + + HandlerRegistryIterator begin() const { + return HandlerRegistryIterator(handler_list_.begin()); + } + + HandlerRegistryIterator end() const { + return HandlerRegistryIterator(handler_list_.end()); + } + + private: + int current_id_ = 1; + std::vector>> handler_list_; +}; +} // namespace cru diff --git a/include/cru/base/PreConfig.h b/include/cru/base/PreConfig.h new file mode 100644 index 00000000..3f26c589 --- /dev/null +++ b/include/cru/base/PreConfig.h @@ -0,0 +1,18 @@ +// IWYU pragma: always_keep + +#pragma once + +#ifdef _MSC_VER +// disable the unnecessary warning about multi-inheritance +#pragma warning(disable : 4250) +// disable dll export template issue warning +#pragma warning(disable : 4251) +#endif + +#ifdef CRU_PLATFORM_WINDOWS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(CRU_PLATFORM_OSX) || defined(CRU_PLATFORM_LINUX) +#define CRU_PLATFORM_UNIX +#endif diff --git a/include/cru/base/PropertyTree.h b/include/cru/base/PropertyTree.h new file mode 100644 index 00000000..54e185b9 --- /dev/null +++ b/include/cru/base/PropertyTree.h @@ -0,0 +1,63 @@ +#pragma once + +#include "Base.h" +#include "String.h" + +#include + +namespace cru { +class PropertyTree; + +class CRU_BASE_API PropertySubTreeRef { + public: + static String CombineKey(StringView left, StringView right); + + explicit PropertySubTreeRef(PropertyTree* tree, String path = {}); + + CRU_DEFAULT_COPY(PropertySubTreeRef); + CRU_DEFAULT_MOVE(PropertySubTreeRef); + + CRU_DEFAULT_DESTRUCTOR(PropertySubTreeRef); + + public: + PropertyTree* GetTree() const { return tree_; } + + String GetPath() const { return path_; } + void SetPath(String path) { path_ = std::move(path); } + + PropertySubTreeRef GetParent() const; + PropertySubTreeRef GetChild(const String& key) const; + + String GetValue(const String& key) const; + void SetValue(const String& key, String value); + void DeleteValue(const String& key); + + private: + PropertyTree* tree_; + String path_; +}; + +class CRU_BASE_API PropertyTree { + public: + static String CombineKey(StringView left, StringView right); + + PropertyTree() = default; + explicit PropertyTree(std::unordered_map values); + + CRU_DELETE_COPY(PropertyTree); + CRU_DELETE_MOVE(PropertyTree); + + CRU_DEFAULT_DESTRUCTOR(PropertyTree); + + public: + String GetValue(const String& key) const; + void SetValue(const String& key, String value); + void DeleteValue(const String& key); + + PropertySubTreeRef GetSubTreeRef(const String& path); + + private: + std::unordered_map values_; +}; + +} // namespace cru diff --git a/include/cru/base/Range.h b/include/cru/base/Range.h new file mode 100644 index 00000000..edc2ec55 --- /dev/null +++ b/include/cru/base/Range.h @@ -0,0 +1,42 @@ +#pragma once +#include "Base.h" + +namespace cru { +struct Range final { + constexpr static Range FromTwoSides(Index start, Index end) { + return Range(start, end - start); + } + + constexpr static Range FromTwoSides(Index start, Index end, Index offset) { + return Range(start + offset, end - start); + } + + constexpr Range() = default; + constexpr Range(const Index position, const Index count = 0) + : position(position), count(count) {} + + Index GetStart() const { return position; } + Index GetEnd() const { return position + count; } + + void ChangeEnd(Index new_end) { count = new_end - position; } + + Range Normalize() const { + auto result = *this; + if (result.count < 0) { + result.position += result.count; + result.count = -result.count; + } + return result; + } + + Range CoerceInto(Index min, Index max) const { + auto coerce = [min, max](Index index) { + return index > max ? max : (index < min ? min : index); + }; + return Range::FromTwoSides(coerce(GetStart()), coerce(GetEnd())); + } + + Index position = 0; + Index count = 0; +}; +} // namespace cru diff --git a/include/cru/base/SelfResolvable.h b/include/cru/base/SelfResolvable.h new file mode 100644 index 00000000..84fa54f6 --- /dev/null +++ b/include/cru/base/SelfResolvable.h @@ -0,0 +1,153 @@ +#pragma once + +#include +#include +#include +#include + +namespace cru { +template +class SelfResolvable; + +template +class ObjectResolver { + friend SelfResolvable; + template + friend class ObjectResolver; + + private: + template + using Accessor_ = std::function&)>; + using ThisAccessor_ = Accessor_; + + explicit ObjectResolver(T* o) + : shared_object_ptr_(new void*(o)), + accessor_([](const std::shared_ptr& ptr) { + return static_cast(*ptr); + }) {} + explicit ObjectResolver(std::shared_ptr ptr, ThisAccessor_ accessor) + : shared_object_ptr_(std::move(ptr)), accessor_(std::move(accessor)) {} + + template + static ThisAccessor_ CreateAccessor(Accessor_ parent_accessor) { + return [parent_accessor = + std::move(parent_accessor)](const std::shared_ptr& ptr) { + return static_cast(parent_accessor(ptr)); + }; + } + + public: + template >> + ObjectResolver(const ObjectResolver& other) + : shared_object_ptr_(other.shared_object_ptr_), + accessor_(CreateAccessor(other.accessor_)) {} + + template >> + ObjectResolver(ObjectResolver&& other) + : shared_object_ptr_(std::move(other.shared_object_ptr_)), + accessor_(CreateAccessor(std::move(other.accessor_))) {} + + ObjectResolver(const ObjectResolver&) = default; + ObjectResolver& operator=(const ObjectResolver&) = default; + ObjectResolver(ObjectResolver&&) = default; + ObjectResolver& operator=(ObjectResolver&&) = default; + ~ObjectResolver() = default; + + template >> + ObjectResolver& operator=(const ObjectResolver& other) { + if (this != &other) { + this->shared_object_ptr_ = other.shared_object_ptr_; + this->accessor_ = CreateAccessor(other.accessor_); + } + return *this; + } + + template >> + ObjectResolver& operator=(ObjectResolver&& other) { + if (this != &other) { + this->shared_object_ptr_ = std::move(other.shared_object_ptr_); + this->accessor_ = CreateAccessor(std::move(other.shared_object_ptr_)); + } + return *this; + } + + bool IsValid() const { return this->shared_object_ptr_ != nullptr; } + + T* Resolve() const { + assert(IsValid()); + return this->accessor_(this->shared_object_ptr_); + } + + /** + * @remarks So this class can be used as a functor. + */ + T* operator()() const { return Resolve(); } + + template >> + operator ObjectResolver() const { + return ObjectResolver(*this); + } + + private: + void SetResolvedObject(T* o) { + assert(IsValid()); + *this->shared_object_ptr_ = o; + } + + private: + std::shared_ptr shared_object_ptr_; + std::function&)> accessor_; +}; + +/** + * @remarks + * This class is not copyable and movable since subclass is polymorphic and + * copying is then nonsense. However, you can even delete move capability in + * subclass because it may also be nonsense for subclass. The move capability is + * optional. + * + * Whether this class needs to be thread-safe still has to be considered. + */ +template +class SelfResolvable { + public: + SelfResolvable() : resolver_(CastToSubClass()) {} + SelfResolvable(const SelfResolvable&) = delete; + SelfResolvable& operator=(const SelfResolvable&) = delete; + + // Resolvers to old object will resolve to new object. + SelfResolvable(SelfResolvable&& other) + : resolver_(std::move(other.resolver_)) { + this->resolver_.SetResolvedObject(CastToSubClass()); + } + + // Old resolvers for this object will resolve to nullptr. + // Other's resolvers will now resolve to this. + SelfResolvable& operator=(SelfResolvable&& other) { + if (this != &other) { + this->resolver_ = std::move(other.resolver_); + this->resolver_.SetResolvedObject(CastToSubClass()); + } + return *this; + } + + virtual ~SelfResolvable() { + if (this->resolver_.IsValid()) { + this->resolver_.SetResolvedObject(nullptr); + } + } + + ObjectResolver CreateResolver() { return resolver_; } + + private: + T* CastToSubClass() { return static_cast(this); } + + private: + ObjectResolver resolver_; +}; +} // namespace cru diff --git a/include/cru/base/String.h b/include/cru/base/String.h new file mode 100644 index 00000000..21a3db51 --- /dev/null +++ b/include/cru/base/String.h @@ -0,0 +1,492 @@ +#pragma once +#include "Base.h" + +#include "Buffer.h" +#include "Range.h" +#include "StringToNumberConverter.h" +#include "StringUtil.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace cru { +class StringView; + +class CRU_BASE_API String { + public: + using value_type = char16_t; + using size_type = Index; + using difference_type = Index; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = value_type*; + using const_iterator = const value_type*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + public: + static String FromUtf8(const char* str); + static String FromUtf8(const char* str, Index size); + static String FromUtf8(const std::byte* str, Index size); + static String FromUtf8(std::string_view str) { + return FromUtf8(str.data(), str.size()); + } + static String FromUtf8(const Buffer& buffer); + + static String FromUtf16(const char16_t* str) { return String(str); } + static String FromUtf16(const char16_t* str, Index size) { + return String(str, size); + } + static String FromUtf16(std::u16string_view str) { + return FromUtf16(str.data(), str.size()); + } + + static inline String From(StringView str); + + // Never use this if you don't know what this mean! + static String FromBuffer(pointer buffer, Index size, Index capacity) { + return String{from_buffer_tag{}, buffer, size, capacity}; + } + + static String FromStdPath(const std::filesystem::path& path); + +#ifdef CRU_PLATFORM_WINDOWS + static String FromUtf16(wchar_t* str) { return String(str); } + static String FromUtf16(wchar_t* str, Index size) { + return String(str, size); + } +#endif + + public: + String() = default; + + String(const_pointer str); + String(const_pointer str, size_type size); + + template + String(const char16_t (&str)[size]) + : String(reinterpret_cast(str), size - 1) {} + + template + String(Iter start, Iter end) { + for (; start != end; start++) { + append(*start); + } + } + + String(size_type size, value_type ch = 0); + + String(std::initializer_list l); + + explicit String(StringView str); + +#ifdef CRU_PLATFORM_WINDOWS + String(const wchar_t* str); + String(const wchar_t* str, Index size); + String(const std::wstring& str) : String(str.data(), str.size()) {} +#endif + + String(const String& other); + String(String&& other) noexcept; + + String& operator=(const String& other); + String& operator=(String&& other) noexcept; + + ~String(); + + private: + struct from_buffer_tag {}; + String(from_buffer_tag, pointer buffer, Index size, Index capacity); + + public: + bool empty() const { return this->size_ == 0; } + Index size() const { return this->size_; } + Index length() const { return this->size(); } + Index capacity() const { return this->capacity_; } + pointer data() { return this->buffer_; } + const_pointer data() const { return this->buffer_; } + + void resize(Index new_size); + void reserve(Index new_capacity); + void shrink_to_fit(); + + reference front() { return this->operator[](0); } + const_reference front() const { return this->operator[](0); } + + reference back() { return this->operator[](size_ - 1); } + const_reference back() const { return this->operator[](size_ - 1); } + + const_pointer c_str() const { return buffer_; } + + reference operator[](Index index) { return buffer_[index]; } + const_reference operator[](Index index) const { return buffer_[index]; } + + public: + iterator begin() { return this->buffer_; } + const_iterator begin() const { return this->buffer_; } + const_iterator cbegin() const { return this->buffer_; } + + iterator end() { return this->buffer_ + this->size_; } + const_iterator end() const { return this->buffer_ + this->size_; } + const_iterator cend() const { return this->buffer_ + this->size_; } + + reverse_iterator rbegin() { return reverse_iterator{end()}; } + const_reverse_iterator rbegin() const { + return const_reverse_iterator{end()}; + } + const_reverse_iterator crbegin() const { + return const_reverse_iterator{cend()}; + } + + reverse_iterator rend() { return reverse_iterator{begin()}; } + const_reverse_iterator rend() const { + return const_reverse_iterator{begin()}; + } + const_reverse_iterator crend() const { + return const_reverse_iterator{cbegin()}; + } + + public: + void clear(); + iterator insert(const_iterator pos, value_type value) { + return this->insert(pos, &value, 1); + } + iterator insert(const_iterator pos, const_iterator str, Index size); + iterator insert(const_iterator pos, StringView str); + iterator erase(const_iterator pos) { return this->erase(pos, pos + 1); } + iterator erase(const_iterator start, const_iterator end); + void push_back(value_type value) { this->append(value); } + void pop_back() { this->erase(cend() - 1); } + void append(value_type value) { this->insert(cend(), value); } + void append(const_iterator str, Index size) { + this->insert(cend(), str, size); + } + inline void append(StringView str); + + String substr(size_type start, size_type size = -1) const { + if (size == -1) { + size = this->size_ - start; + } + return String(this->buffer_ + start, size); + } + + String& operator+=(value_type value) { + this->append(value); + return *this; + } + String& operator+=(StringView other); + + public: + operator std::u16string_view() const { + return std::u16string_view(data(), size()); + } + + StringView View() const; + + public: + Index Find(value_type value, Index start = 0) const; + std::vector Split(value_type separator, + bool remove_space_line = false) const; + std::vector SplitToLines(bool remove_space_line = false) const; + + bool StartWith(StringView str) const; + bool EndWith(StringView str) const; + + String& TrimStart(); + String& TrimEnd(); + String& Trim(); + + public: + void AppendCodePoint(CodePoint code_point); + + Utf16CodePointIterator CodePointIterator() const { + return Utf16CodePointIterator(buffer_, size_); + } + + Index IndexFromCodeUnitToCodePoint(Index code_unit_index) const; + Index IndexFromCodePointToCodeUnit(Index code_point_index) const; + Range RangeFromCodeUnitToCodePoint(Range code_unit_range) const; + Range RangeFromCodePointToCodeUnit(Range code_point_range) const; + + template + std::enable_if_t, TInteger> ParseToInteger( + Index* processed_characters_count, unsigned flags, int base) const; + + int ParseToInt(Index* processed_characters_count = nullptr, + StringToNumberFlag flags = {}, int base = 0) const; + long long ParseToLongLong(Index* processed_characters_count = nullptr, + StringToNumberFlag flags = {}, int base = 0) const; + + float ParseToFloat(Index* processed_characters_count = nullptr, + StringToNumberFlag flags = {}) const; + double ParseToDouble(Index* processed_characters_count = nullptr, + StringToNumberFlag flags = {}) const; + std::vector ParseToFloatList(value_type separator = u' ') const; + std::vector ParseToDoubleList(value_type separator = u' ') const; + +#ifdef CRU_PLATFORM_WINDOWS + const wchar_t* WinCStr() const { + return reinterpret_cast(c_str()); + } +#endif + + template + String Format(T&&... args) const; + + std::string ToUtf8() const; + Buffer ToUtf8Buffer(bool end_zero = true) const; + + int Compare(const String& other) const; + int CaseInsensitiveCompare(const String& other) const; + bool CaseInsensitiveEqual(const String& other) const { + return CaseInsensitiveCompare(other) == 0; + } + + private: + static char16_t kEmptyBuffer[1]; + + private: + char16_t* buffer_ = kEmptyBuffer; + Index size_ = 0; // not including trailing '\0' + Index capacity_ = 0; // always 1 smaller than real buffer size +}; + +std::ostream& CRU_BASE_API operator<<(std::ostream& os, const String& value); + +class CRU_BASE_API StringView { + public: + using value_type = char16_t; + using size_type = Index; + using difference_type = Index; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = const value_type*; + using const_iterator = const value_type*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + StringView() = default; + + constexpr StringView(const_pointer ptr, Index size) + : ptr_(ptr), size_(size) {} + + template + constexpr StringView(const value_type (&array)[size]) + : StringView(array, size - 1) {} + + StringView(const String& str) : StringView(str.data(), str.size()) {} + + CRU_DEFAULT_COPY(StringView) + CRU_DEFAULT_MOVE(StringView) + + ~StringView() = default; + + bool empty() const { return size_ == 0; } + Index size() const { return size_; } + const value_type* data() const { return ptr_; } + + public: + iterator begin() { return this->ptr_; } + const_iterator begin() const { return this->ptr_; } + const_iterator cbegin() const { return this->ptr_; } + + iterator end() { return this->ptr_ + this->size_; } + const_iterator end() const { return this->ptr_ + this->size_; } + const_iterator cend() const { return this->ptr_ + this->size_; } + + reverse_iterator rbegin() { return reverse_iterator{end()}; } + const_reverse_iterator rbegin() const { + return const_reverse_iterator{end()}; + } + const_reverse_iterator crbegin() const { + return const_reverse_iterator{cend()}; + } + + reverse_iterator rend() { return reverse_iterator{begin()}; } + const_reverse_iterator rend() const { + return const_reverse_iterator{begin()}; + } + const_reverse_iterator crend() const { + return const_reverse_iterator{cbegin()}; + } + + StringView substr(Index pos); + StringView substr(Index pos, Index size); + + value_type operator[](Index index) const { return ptr_[index]; } + + operator std::u16string_view() const { + return std::u16string_view(data(), size()); + } + + public: + int Compare(const StringView& other) const; + int CaseInsensitiveCompare(const StringView& other) const; + bool CaseInsensitiveEqual(const StringView& other) const { + return CaseInsensitiveCompare(other) == 0; + } + + String ToString() const { return String(ptr_, size_); } + + Utf16CodePointIterator CodePointIterator() const { + return Utf16CodePointIterator(ptr_, size_); + } + + Index Find(value_type value, Index start = 0) const; + std::vector Split(value_type separator, + bool remove_space_line = false) const; + std::vector SplitToLines(bool remove_space_line = false) const; + + bool StartWith(StringView str) const; + bool EndWith(StringView str) const; + + Index IndexFromCodeUnitToCodePoint(Index code_unit_index) const; + Index IndexFromCodePointToCodeUnit(Index code_point_index) const; + Range RangeFromCodeUnitToCodePoint(Range code_unit_range) const; + Range RangeFromCodePointToCodeUnit(Range code_point_range) const; + + template + std::enable_if_t, TInteger> ParseToInteger( + Index* processed_characters_count, StringToNumberFlag flags, + int base) const { + auto utf8_string = ToUtf8(); + auto result = StringToIntegerConverter(flags, base) + .Parse(utf8_string.data(), utf8_string.size(), + processed_characters_count); + return result.negate ? -result.value : result.value; + } + + int ParseToInt(Index* processed_characters_count = nullptr, + StringToNumberFlag flags = {}, int base = 0) const; + long long ParseToLongLong(Index* processed_characters_count = nullptr, + StringToNumberFlag flags = {}, int base = 0) const; + + float ParseToFloat(Index* processed_characters_count = nullptr, + StringToNumberFlag flags = {}) const; + double ParseToDouble(Index* processed_characters_count = nullptr, + StringToNumberFlag flags = {}) const; + std::vector ParseToFloatList(value_type separator = u' ') const; + std::vector ParseToDoubleList(value_type separator = u' ') const; + + std::string ToUtf8() const; + Buffer ToUtf8Buffer(bool end_zero = true) const; + + private: + const char16_t* ptr_; + Index size_; +}; + +CRU_DEFINE_COMPARE_OPERATORS(String) + +inline String operator+(const String& left, const String& right) { + String result; + result += left; + result += right; + return result; +} + +inline String operator+(String::value_type left, const String& right) { + String result; + result += left; + result += right; + return result; +} + +inline String operator+(const String& left, String::value_type right) { + String result; + result += left; + result += right; + return result; +} + +CRU_DEFINE_COMPARE_OPERATORS(StringView) + +inline String::iterator String::insert(const_iterator pos, StringView str) { + return insert(pos, str.data(), str.size()); +} + +inline void String::append(StringView str) { + this->append(str.data(), str.size()); +} + +inline String String::From(StringView str) { return str.ToString(); } + +inline String::String(StringView str) : String(str.data(), str.size()) {} + +inline String ToString(StringView value) { return value.ToString(); } + +inline CodePoint Utf16PreviousCodePoint(StringView str, Index current, + Index* previous_position) { + return Utf16PreviousCodePoint(str.data(), str.size(), current, + previous_position); +} + +inline CodePoint Utf16NextCodePoint(StringView str, Index current, + Index* next_position) { + return Utf16NextCodePoint(str.data(), str.size(), current, next_position); +} + +inline bool Utf16IsValidInsertPosition(StringView str, Index position) { + return Utf16IsValidInsertPosition(str.data(), str.size(), position); +} + +// Return position after the character making predicate returns true or 0 if no +// character doing so. +inline Index CRU_BASE_API +Utf16BackwardUntil(StringView str, Index position, + const std::function& predicate) { + return Utf16BackwardUntil(str.data(), str.size(), position, predicate); +} +// Return position before the character making predicate returns true or +// str.size() if no character doing so. +inline Index CRU_BASE_API +Utf16ForwardUntil(StringView str, Index position, + const std::function& predicate) { + return Utf16ForwardUntil(str.data(), str.size(), position, predicate); +} + +inline Index Utf16PreviousWord(StringView str, Index position, + bool* is_space = nullptr) { + return Utf16PreviousWord(str.data(), str.size(), position, is_space); +} + +inline Index Utf16NextWord(StringView str, Index position, + bool* is_space = nullptr) { + return Utf16NextWord(str.data(), str.size(), position, is_space); +} + +String CRU_BASE_API ToLower(StringView s); +String CRU_BASE_API ToUpper(StringView s); + +template +std::enable_if_t, TInteger> String::ParseToInteger( + Index* processed_characters_count, unsigned flags, int base) const { + View().ParseToInteger(processed_characters_count, flags, base); +} + +} // namespace cru + +template <> +struct std::hash { + std::size_t operator()(const cru::String& value) const { + return std::hash{}(std::u16string_view( + reinterpret_cast(value.data()), value.size())); + } +}; + +template <> +struct std::hash { + std::size_t operator()(const cru::StringView& value) const { + return std::hash{}(std::u16string_view( + reinterpret_cast(value.data()), value.size())); + } +}; diff --git a/include/cru/base/StringToNumberConverter.h b/include/cru/base/StringToNumberConverter.h new file mode 100644 index 00000000..758b26c8 --- /dev/null +++ b/include/cru/base/StringToNumberConverter.h @@ -0,0 +1,107 @@ +#pragma once +#include "Base.h" +#include "Bitmask.h" + +#include +#include + +namespace cru { +namespace details { +struct StringToNumberFlagTag {}; +} // namespace details + +using StringToNumberFlag = Bitmask; + +struct StringToNumberFlags { + constexpr static StringToNumberFlag kAllowLeadingSpaces = + StringToNumberFlag::FromOffset(0); + constexpr static StringToNumberFlag kAllowTrailingSpaces = + StringToNumberFlag::FromOffset(1); + constexpr static StringToNumberFlag kAllowTrailingJunk = + StringToNumberFlag::FromOffset(2); + constexpr static StringToNumberFlag kAllowLeadingZeroForInteger = + StringToNumberFlag::FromOffset(3); + constexpr static StringToNumberFlag kThrowOnError = + StringToNumberFlag::FromOffset(4); +}; + +template +struct IStringToNumberConverter : virtual Interface { + virtual TResult Parse(const char* str, Index size, + Index* processed_characters_count) const = 0; + + template + TResult Parse(const char (&str)[Size], + Index* processed_characters_count) const { + return Parse(str, Size - 1, processed_characters_count); + } +}; + +struct CRU_BASE_API StringToIntegerResult { + StringToIntegerResult() = default; + StringToIntegerResult(bool negate, unsigned long long value) + : negate(negate), value(value) {} + + bool negate; + unsigned long long value; +}; + +inline bool CRU_BASE_API operator==(const StringToIntegerResult& left, + const StringToIntegerResult& right) { + return left.negate == right.negate && left.value == right.value; +} + +inline bool CRU_BASE_API operator!=(const StringToIntegerResult& left, + const StringToIntegerResult& right) { + return !(left == right); +} + +inline std::ostream& CRU_BASE_API +operator<<(std::ostream& stream, const StringToIntegerResult& result) { + return stream << "StringToIntegerConverterImplResult(" + << (result.negate ? "-" : "") << result.value << ")"; +} + +/** + * \brief A converter that convert number into long long. + */ +struct CRU_BASE_API StringToIntegerConverter + : IStringToNumberConverter { + public: + explicit StringToIntegerConverter(StringToNumberFlag flags, int base = 0) + : flags(flags), base(base) {} + + bool CheckParams() const; + + /** + * \brief Convert string to long long. + * \param str The string to convert. + * \param size The size of the string. + * \param processed_characters_count The number of characters that were + * processed. Or nullptr to not retrieve. + */ + StringToIntegerResult Parse(const char* str, Index size, + Index* processed_characters_count) const override; + using IStringToNumberConverter::Parse; + + StringToNumberFlag flags; + /** + * \brief The base of the number used for parse or 0 for auto detect. + * \remarks Base can only be of range [2, 36] or 0. If base is 0, decimal is + * assumed by default ,or if str is started with "0x" or "0X" hexadecimal is + * assumed, or if str is started with a single "0" octoral is assumed, or if + * str is started with "0b" or "0B" binary is assumed. Otherwise it is an + * error. + */ + int base; +}; + +struct CRU_BASE_API StringToFloatConverter { + StringToFloatConverter(StringToNumberFlag flags) : flags(flags) {} + + double Parse(const char* str, Index size, + Index* processed_characters_count) const; + + StringToNumberFlag flags; +}; +} // namespace cru diff --git a/include/cru/base/StringUtil.h b/include/cru/base/StringUtil.h new file mode 100644 index 00000000..8f085283 --- /dev/null +++ b/include/cru/base/StringUtil.h @@ -0,0 +1,226 @@ +#pragma once +#include "Base.h" + +#include +#include + +namespace cru { +using CodePoint = std::int32_t; +constexpr CodePoint k_invalid_code_point = -1; + +inline bool IsUtf16SurrogatePairCodeUnit(char16_t c) { + return c >= 0xD800 && c <= 0xDFFF; +} + +inline bool IsUtf16SurrogatePairLeading(char16_t c) { + return c >= 0xD800 && c <= 0xDBFF; +} + +inline bool IsUtf16SurrogatePairTrailing(char16_t c) { + return c >= 0xDC00 && c <= 0xDFFF; +} + +CodePoint CRU_BASE_API Utf8NextCodePoint(const char* ptr, Index size, + Index current, Index* next_position); + +CodePoint CRU_BASE_API Utf16NextCodePoint(const char16_t* ptr, Index size, + Index current, Index* next_position); +CodePoint CRU_BASE_API Utf16PreviousCodePoint(const char16_t* ptr, Index size, + Index current, + Index* previous_position); + +template +using NextCodePointFunctionType = CodePoint (*)(const CharType*, Index, Index, + Index*); + +template NextCodePointFunction> +class CodePointIterator { + public: + using difference_type = Index; + using value_type = CodePoint; + using pointer = void; + using reference = value_type; + using iterator_category = std::forward_iterator_tag; + + public: + struct past_end_tag_t {}; + + explicit CodePointIterator(const CharType* ptr, Index size, Index current = 0) + : ptr_(ptr), size_(size), position_(current) {} + explicit CodePointIterator(const CharType* ptr, Index size, past_end_tag_t) + : ptr_(ptr), size_(size), position_(size) {} + + CRU_DEFAULT_COPY(CodePointIterator) + CRU_DEFAULT_MOVE(CodePointIterator) + + ~CodePointIterator() = default; + + public: + const CharType* GetPtr() const { return ptr_; } + Index GetSize() const { return size_; } + Index GetPosition() const { return position_; } + + bool IsPastEnd() const { return position_ == static_cast(size_); } + + public: + CodePointIterator begin() const { return *this; } + CodePointIterator end() const { + return CodePointIterator{ptr_, size_, past_end_tag_t{}}; + } + + public: + bool operator==(const CodePointIterator& other) const { + // You should compare iterator that iterate on the same string. + Expects(this->ptr_ == other.ptr_ && this->size_ == other.size_); + return this->position_ == other.position_; + } + bool operator!=(const CodePointIterator& other) const { + return !this->operator==(other); + } + + CodePointIterator& operator++() { + Expects(!IsPastEnd()); + Forward(); + return *this; + } + + CodePointIterator operator++(int) { + Expects(!IsPastEnd()); + CodePointIterator old = *this; + Forward(); + return old; + } + + CodePoint operator*() const { + return NextCodePointFunction(ptr_, size_, position_, &next_position_cache_); + } + + private: + void Forward() { + if (next_position_cache_ > position_) { + position_ = next_position_cache_; + } else { + NextCodePointFunction(ptr_, size_, position_, &position_); + } + } + + private: + const CharType* ptr_; + Index size_; + Index position_; + mutable Index next_position_cache_ = 0; +}; + +using Utf8CodePointIterator = CodePointIterator; + +using Utf16CodePointIterator = CodePointIterator; + +namespace details { +template +inline std::enable_if_t, ReturnType> ExtractBits( + UInt n) { + return static_cast(n & ((1u << number_of_bit) - 1)); +} +} // namespace details + +template +std::enable_if_t, bool> +Utf8EncodeCodePointAppend(CodePoint code_point, CharWriter&& writer) { + auto write_continue_byte = [&writer](std::uint8_t byte6) { + writer((1u << 7) + (((1u << 6) - 1) & byte6)); + }; + + if (code_point >= 0 && code_point <= 0x007F) { + writer(static_cast(code_point)); + return true; + } else if (code_point >= 0x0080 && code_point <= 0x07FF) { + std::uint32_t unsigned_code_point = code_point; + writer( + static_cast(details::ExtractBits( + (unsigned_code_point >> 6)) + + 0b11000000)); + write_continue_byte(details::ExtractBits( + unsigned_code_point)); + return true; + } else if (code_point >= 0x0800 && code_point <= 0xFFFF) { + std::uint32_t unsigned_code_point = code_point; + writer( + static_cast(details::ExtractBits( + (unsigned_code_point >> (6 * 2))) + + 0b11100000)); + write_continue_byte(details::ExtractBits( + unsigned_code_point >> 6)); + write_continue_byte(details::ExtractBits( + unsigned_code_point)); + return true; + } else if (code_point >= 0x10000 && code_point <= 0x10FFFF) { + std::uint32_t unsigned_code_point = code_point; + writer( + static_cast(details::ExtractBits( + (unsigned_code_point >> (6 * 3))) + + 0b11110000)); + write_continue_byte(details::ExtractBits( + unsigned_code_point >> (6 * 2))); + write_continue_byte(details::ExtractBits( + unsigned_code_point >> 6)); + write_continue_byte(details::ExtractBits( + unsigned_code_point)); + return true; + } else { + return false; + } +} + +template +std::enable_if_t, bool> +Utf16EncodeCodePointAppend(CodePoint code_point, CharWriter&& writer) { + if ((code_point >= 0 && code_point <= 0xD7FF) || + (code_point >= 0xE000 && code_point <= 0xFFFF)) { + writer(static_cast(code_point)); + return true; + } else if (code_point >= 0x10000 && code_point <= 0x10FFFF) { + std::uint32_t u = code_point - 0x10000; + writer(static_cast( + details::ExtractBits(u >> 10) + + 0xD800u)); + writer(static_cast( + details::ExtractBits(u) + 0xDC00u)); + return true; + } else { + return false; + } +} + +// If given s is not a valid utf16 string, return value is UD. +bool CRU_BASE_API Utf16IsValidInsertPosition(const char16_t* ptr, Index size, + Index position); + +// Return position after the character making predicate returns true or 0 if no +// character doing so. +Index CRU_BASE_API +Utf16BackwardUntil(const char16_t* ptr, Index size, Index position, + const std::function& predicate); +// Return position before the character making predicate returns true or +// str.size() if no character doing so. +Index CRU_BASE_API +Utf16ForwardUntil(const char16_t* ptr, Index size, Index position, + const std::function& predicate); + +Index CRU_BASE_API Utf16PreviousWord(const char16_t* ptr, Index size, + Index position, bool* is_space = nullptr); +Index CRU_BASE_API Utf16NextWord(const char16_t* ptr, Index size, + Index position, bool* is_space = nullptr); + +char16_t CRU_BASE_API ToLower(char16_t c); +char16_t CRU_BASE_API ToUpper(char16_t c); + +bool CRU_BASE_API IsWhitespace(char16_t c); +bool CRU_BASE_API IsDigit(char16_t c); + +Utf8CodePointIterator CRU_BASE_API CreateUtf8Iterator(const std::byte* buffer, + Index size); +Utf8CodePointIterator CRU_BASE_API +CreateUtf8Iterator(const std::vector& buffer); + +} // namespace cru diff --git a/include/cru/base/SubProcess.h b/include/cru/base/SubProcess.h new file mode 100644 index 00000000..fbe8ad2b --- /dev/null +++ b/include/cru/base/SubProcess.h @@ -0,0 +1,258 @@ +#pragma once +#include "Base.h" +#include "Exception.h" +#include "String.h" +#include "io/Stream.h" + +#include +#include +#include +#include +#include +#include + +namespace cru { +enum class SubProcessStatus { + /** + * @brief The process has not been created and started. + */ + Prepare, + /** + * @brief The process is failed to start. + */ + FailedToStart, + /** + * @brief The process is running now. + */ + Running, + /** + * @brief The process has been exited. + */ + Exited, +}; + +class CRU_BASE_API SubProcessException : public Exception { + public: + using Exception::Exception; +}; + +class CRU_BASE_API SubProcessFailedToStartException + : public SubProcessException { + public: + using SubProcessException::SubProcessException; +}; + +class CRU_BASE_API SubProcessInternalException : public SubProcessException { + public: + using SubProcessException::SubProcessException; +}; + +struct SubProcessStartInfo { + String program; + std::vector arguments; + std::unordered_map environments; +}; + +enum class SubProcessExitType { + Unknown, + Normal, + Signal, +}; + +struct SubProcessExitResult { + SubProcessExitType exit_type; + int exit_code; + int exit_signal; + bool has_core_dump; + + bool IsSuccess() const { + return exit_type == SubProcessExitType::Normal && exit_code == 0; + } + + static SubProcessExitResult Unknown() { + return {SubProcessExitType::Unknown, 0, 0, false}; + } + + static SubProcessExitResult Normal(int exit_code) { + return {SubProcessExitType::Normal, exit_code, 0, false}; + } + + static SubProcessExitResult Signal(int exit_signal, bool has_core_dump) { + return {SubProcessExitType::Normal, 0, exit_signal, has_core_dump}; + } +}; + +struct IPlatformSubProcessImpl : virtual Interface { + /** + * @brief Create and start a real process. + * + * If the program can't be created or start, an exception should be + * thrown. + * + * Implementation should fill internal data of the new process and start + * it. + * + * This method will be called only once in first call of `Start` on this + * thread with lock holdDefaultConstructible. + */ + virtual void PlatformCreateProcess(const SubProcessStartInfo& start_info) = 0; + + /** + * @brief Wait for the created process forever and return the exit result + * when process stops. + * + * Implementation should wait for the real process forever, after that, + * fill internal data and returns exit result. + * + * This method will be called only once on another thread after + * `PlatformCreateProcess` returns successfully + */ + virtual SubProcessExitResult PlatformWaitForProcess() = 0; + + /** + * @brief Kill the process immediately. + * + * This method will be called only once on this thread given + * `PlatformCreateProcess` returns successfully. There will be a window + * that the window already exits but the status has not been updated and + * this is called. So handle this gracefully and write to internal data + * carefully. + */ + virtual void PlatformKillProcess() = 0; + + virtual io::Stream* GetStdinStream() = 0; + virtual io::Stream* GetStdoutStream() = 0; + virtual io::Stream* GetStderrStream() = 0; +}; + +/** + * @brief A wrapper platform process. It is one-time, which means it + * starts and exits and can't start again. + * + * TODO: Current implementation has a problem. If the process does not exit for + * a long time, the resource related to it will not be released. It may cause a + * leak. + */ +class PlatformSubProcess : public Object { + CRU_DEFINE_CLASS_LOG_TAG(u"PlatformSubProcess") + + private: + struct State { + explicit State(SubProcessStartInfo start_info, + std::shared_ptr impl) + : start_info(std::move(start_info)), impl(std::move(impl)) {} + + std::mutex mutex; + std::condition_variable condition_variable; + SubProcessStartInfo start_info; + SubProcessExitResult exit_result; + SubProcessStatus status = SubProcessStatus::Prepare; + bool killed = false; + std::shared_ptr impl; + }; + + public: + PlatformSubProcess(SubProcessStartInfo start_info, + std::shared_ptr impl); + + ~PlatformSubProcess() override; + + /** + * @brief Create and start a real process. If the process can't be created or + * start, `SubProcessFailedToStartException` will be thrown. If this function + * is already called once, `SubProcessException` will be thrown. Ensure only + * call this method once. + */ + void Start(); + + /** + * @brief Wait for the process to exit optionally for at most `wait_time`. If + * the process already exits, it will return immediately. If the process has + * not started or failed to start, `SubProcessException` will be thrown. + * Ensure `Start` is called and does not throw before calling this. + * + * @remarks You may wish this returns bool to indicate whether it is timeout + * or the process exits. But no, even if it is timeout, the process may also + * have exited due to task schedule. + */ + void Wait(std::optional wait_time); + + /** + * @brief kill the process if it is running. If the process already exits, + * nothing will happen. If the process has not started or failed to start, + * `SubProcessException` will be throw. Ensure `Start` is called and does not + * throw before calling this. + */ + void Kill(); + + /** + * @brief Get the status of the process. + * 1. If the process has tried to start, aka `Start` is called, then this + * method will return one of `Running`, `FailedToStart`, `Exited`. + * 2. If it returns `Prepare`, `Start` is not called. + * 3. It does NOT guarantee that this return `Running` and the process is + * actually running. Because there might be a window that the process exits + * already but status is not updated. + */ + SubProcessStatus GetStatus(); + + /** + * @brief Get the exit result. If the process is not started, failed to start + * or running, `SubProcessException` will be thrown. + */ + SubProcessExitResult GetExitResult(); + + io::Stream* GetStdinStream(); + io::Stream* GetStdoutStream(); + io::Stream* GetStderrStream(); + + private: + std::shared_ptr state_; + std::unique_lock lock_; +}; + +class CRU_BASE_API SubProcess : public Object { + CRU_DEFINE_CLASS_LOG_TAG(u"SubProcess") + + public: + static SubProcess Create( + String program, std::vector arguments = {}, + std::unordered_map environments = {}); + + static SubProcessExitResult Call( + String program, std::vector arguments = {}, + std::unordered_map environments = {}); + + public: + SubProcess(SubProcessStartInfo start_info); + + CRU_DELETE_COPY(SubProcess) + + SubProcess(SubProcess&& other) = default; + SubProcess& operator=(SubProcess&& other) = default; + + ~SubProcess() override; + + public: + void Wait(std::optional wait_time = std::nullopt); + void Kill(); + + SubProcessStatus GetStatus(); + SubProcessExitResult GetExitResult(); + + io::Stream* GetStdinStream(); + io::Stream* GetStdoutStream(); + io::Stream* GetStderrStream(); + + void Detach(); + + bool IsValid() const { return platform_process_ != nullptr; } + explicit operator bool() const { return IsValid(); } + + private: + void CheckValid() const; + + private: + std::unique_ptr platform_process_; +}; +} // namespace cru diff --git a/include/cru/base/concurrent/ConcurrentQueue.h b/include/cru/base/concurrent/ConcurrentQueue.h new file mode 100644 index 00000000..e311d5f9 --- /dev/null +++ b/include/cru/base/concurrent/ConcurrentQueue.h @@ -0,0 +1,88 @@ +#pragma once +#include +#include +#include +#include + +namespace cru::concurrent { +namespace details { +template +struct ConcurrentQueueNode { + ConcurrentQueueNode(T&& value, ConcurrentQueueNode* next = nullptr) + : value(std::move(value)), next(next) {} + + T value; + ConcurrentQueueNode* next; +}; +} // namespace details + +template +class ConcurrentQueue { + public: + ConcurrentQueue() {} + + ConcurrentQueue(const ConcurrentQueue&) = delete; + ConcurrentQueue& operator=(const ConcurrentQueue&) = delete; + + ~ConcurrentQueue() { + if (head_) { + auto node = head_; + while (node) { + auto next = node->next; + delete node; + node = next; + } + } + } + + public: + void Push(T&& value) { + std::unique_lock lock(mutex_); + if (head_ == nullptr) { + head_ = tail_ = new details::ConcurrentQueueNode(std::move(value)); + condition_variable_.notify_one(); + } else { + tail_->next = new details::ConcurrentQueueNode(std::move(value)); + tail_ = tail_->next; + } + } + + T Pull() { + std::unique_lock lock(mutex_); + if (head_ == nullptr) { + condition_variable_.wait(lock); + } + assert(head_ != nullptr); + auto value = std::move(head_->value); + auto next = head_->next; + delete head_; + head_ = next; + if (next == nullptr) { + tail_ = nullptr; + } + return value; + } + + std::optional Poll() { + std::unique_lock lock(mutex_); + if (head_ == nullptr) { + return std::nullopt; + } + auto value = std::move(head_->value); + auto next = head_->next; + delete head_; + head_ = next; + if (next == nullptr) { + tail_ = nullptr; + } + return value; + } + + private: + details::ConcurrentQueueNode* head_ = nullptr; + details::ConcurrentQueueNode* tail_ = nullptr; + + std::mutex mutex_; + std::condition_variable condition_variable_; +}; +} // namespace cru::concurrent diff --git a/include/cru/base/io/AutoReadStream.h b/include/cru/base/io/AutoReadStream.h new file mode 100644 index 00000000..759d5026 --- /dev/null +++ b/include/cru/base/io/AutoReadStream.h @@ -0,0 +1,72 @@ +#pragma once + +#include "BufferStream.h" +#include "Stream.h" + +#include +#include + +namespace cru::io { +struct AutoReadStreamOptions { + /** + * @brief Will be passed to BufferStreamOptions::block_size. + */ + Index block_size = 0; + + /** + * @brief Will be passed to BufferStreamOptions::total_size_limit. + */ + Index total_size_limit = 0; + + BufferStreamOptions GetBufferStreamOptions() const { + BufferStreamOptions options; + options.block_size = block_size; + options.total_size_limit = total_size_limit; + return options; + } +}; + +/** + * @brief A stream that wraps another stream and auto read it into a buffer in a + * background thread. + */ +class CRU_BASE_API AutoReadStream : public Stream { + public: + /** + * @brief Wrap a stream and auto read it in background. + * @param stream The stream to auto read. + * @param auto_delete Whether to delete the stream object in destructor. + * @param options Options to modify the behavior. + */ + AutoReadStream( + Stream* stream, bool auto_delete, + const AutoReadStreamOptions& options = AutoReadStreamOptions()); + + ~AutoReadStream() override; + + public: + CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE + + void BeginToDrop(bool auto_delete = true); + + protected: + Index DoRead(std::byte* buffer, Index offset, Index size) override; + Index DoWrite(const std::byte* buffer, Index offset, Index size) override; + void DoFlush() override; + + private: + void DoClose(); + + void BackgroundThreadRun(); + + private: + Stream* stream_; + bool auto_delete_; + + Index size_per_read_; + std::unique_ptr buffer_stream_; + std::mutex buffer_stream_mutex_; + + std::thread background_thread_; +}; +} // namespace cru::io diff --git a/include/cru/base/io/BufferStream.h b/include/cru/base/io/BufferStream.h new file mode 100644 index 00000000..5ebff546 --- /dev/null +++ b/include/cru/base/io/BufferStream.h @@ -0,0 +1,85 @@ +#pragma once + +#include "../Buffer.h" +#include "../Exception.h" +#include "Stream.h" + +#include +#include +#include + +namespace cru::io { +class WriteAfterEofException : public Exception { + public: + using Exception::Exception; + ~WriteAfterEofException() override = default; +}; + +struct BufferStreamOptions { + /** + * Actually I have no ideas about the best value for this. May change it later + * when I get some ideas. + */ + constexpr static Index kDefaultBlockSize = 1024; + + /** + * @brief The size of a single buffer allocated each time new space is needed. + * Use default value if <= 0. + * + * When current buffer is full and there is no space for following data, a new + * buffer will be allocated and appended to the buffer list. Note if sum size + * of all buffers reaches the total_buffer_limit, no more buffer will be + * allocated but wait. + */ + Index block_size = 0; + + /** + * @brief Total size limit of saved data in buffer. No limit if <= 0. + * + * The size will be floor(total_size_limit / block_size). When the buffer is + * filled, it will block and wait for user to read to get free space of buffer + * to continue read. + */ + Index total_size_limit = 0; + + Index GetBlockSizeOrDefault() const { + return block_size <= 0 ? kDefaultBlockSize : block_size; + } + + Index GetMaxBlockCount() const { + return total_size_limit / GetBlockSizeOrDefault(); + } +}; + +/** + * @brief SPSC (Single Producer Single Consumer) buffer stream. + * + * If used by multiple producer or multiple consumer, the behavior is undefined. + */ +class BufferStream : public Stream { + public: + BufferStream(const BufferStreamOptions& options); + ~BufferStream() override; + + CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE + + void SetEof(); + + protected: + Index DoRead(std::byte* buffer, Index offset, Index size) override; + Index DoWrite(const std::byte* buffer, Index offset, Index size) override; + + private: + void DoClose(); + + private: + Index block_size_; + Index max_block_count_; + + std::list buffer_list_; + bool eof_; + + std::mutex mutex_; + std::condition_variable condition_variable_; +}; +} // namespace cru::io diff --git a/include/cru/base/io/CFileStream.h b/include/cru/base/io/CFileStream.h new file mode 100644 index 00000000..0b58bdc9 --- /dev/null +++ b/include/cru/base/io/CFileStream.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Stream.h" + +#include + +namespace cru::io { +class CRU_BASE_API CFileStream : public Stream { + public: + CFileStream(const char* path, const char* mode); + explicit CFileStream(std::FILE* file, bool readable = true, + bool writable = true, bool auto_close = true); + + CRU_DELETE_COPY(CFileStream) + CRU_DELETE_MOVE(CFileStream) + + ~CFileStream() override; + + public: + CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE + + std::FILE* GetHandle() const; + + protected: + Index DoSeek(Index offset, SeekOrigin origin) override; + Index DoTell() override; + void DoRewind() override; + Index DoRead(std::byte* buffer, Index offset, Index size) override; + Index DoWrite(const std::byte* buffer, Index offset, Index size) override; + void DoFlush() override; + + private: + void DoClose(); + + private: + std::FILE* file_; + bool auto_close_; +}; +} // namespace cru::io diff --git a/include/cru/base/io/MemoryStream.h b/include/cru/base/io/MemoryStream.h new file mode 100644 index 00000000..a1f90c3b --- /dev/null +++ b/include/cru/base/io/MemoryStream.h @@ -0,0 +1,36 @@ +#pragma once + +#include "Stream.h" + +#include + +namespace cru::io { +class CRU_BASE_API MemoryStream : public Stream { + public: + MemoryStream( + std::byte* buffer, Index size, bool read_only = false, + std::function release_func = {}); + + ~MemoryStream() override; + + public: + void Close() override; + + std::byte* GetBuffer() const { return buffer_; } + + protected: + Index DoSeek(Index offset, SeekOrigin origin) override; + Index DoGetSize() override { return size_; } + Index DoRead(std::byte* buffer, Index offset, Index size) override; + Index DoWrite(const std::byte* buffer, Index offset, Index size) override; + + private: + void DoClose(); + + private: + std::byte* buffer_; + Index size_; + Index position_; + std::function release_func_; +}; +} // namespace cru::io diff --git a/include/cru/base/io/OpenFileFlag.h b/include/cru/base/io/OpenFileFlag.h new file mode 100644 index 00000000..4a5789fb --- /dev/null +++ b/include/cru/base/io/OpenFileFlag.h @@ -0,0 +1,56 @@ +#pragma once + +#include "../Bitmask.h" + +namespace cru::io { +namespace details { +struct OpenFileFlagTag {}; +} // namespace details +using OpenFileFlag = Bitmask; + +struct OpenFileFlags { + /** + * \brief for reading + * If the file does not exist, FileNotExistException should be thrown. + */ + static constexpr OpenFileFlag Read{0x1}; + + /** + * \brief for writing + * If the file does not exist and Create is not specified, + * FileNotExistException should be thrown. + */ + static constexpr OpenFileFlag Write{0x2}; + + /** + * \brief when writing, seek to end first + * Only effective for writing. + */ + static constexpr OpenFileFlag Append{0x4}; + + /** + * \brief when writing, truncate the file to empty + * Only effective for writing. + * So the content is erased! Be careful! + */ + static constexpr OpenFileFlag Truncate{0x8}; + + /** + * \brief when writing, if the file does not exist, create one + * Only effective for writing. When file does not exist, FileNotExistException + * will NOT be thrown and a new file will be created. + */ + static constexpr OpenFileFlag Create{0x10}; + + /** + * TODO: ??? + */ + static constexpr OpenFileFlag Exclusive{0x20}; +}; + +/** + * Append, Truncate, Create must be used with Write. + * Append and Truncate must not be used together. + */ +bool CheckOpenFileFlag(OpenFileFlag flags); +} // namespace cru::io diff --git a/include/cru/base/io/ProxyStream.h b/include/cru/base/io/ProxyStream.h new file mode 100644 index 00000000..42ec9dfd --- /dev/null +++ b/include/cru/base/io/ProxyStream.h @@ -0,0 +1,42 @@ +#pragma once + +#include "Stream.h" + +#include + +namespace cru::io { +struct ProxyStreamHandlers { + std::function seek; + std::function read; + std::function write; + std::function flush; + + /** + * @brief This method will be only called once when `Close` is called or the + * stream is destructed. + */ + std::function close; +}; + +class ProxyStream : public Stream { + public: + explicit ProxyStream(ProxyStreamHandlers handlers); + + ~ProxyStream() override; + + public: + CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE + + protected: + Index DoSeek(Index offset, SeekOrigin origin) override; + Index DoRead(std::byte* buffer, Index offset, Index size) override; + Index DoWrite(const std::byte* buffer, Index offset, Index size) override; + void DoFlush() override; + + private: + void DoClose(); + + private: + ProxyStreamHandlers handlers_; +}; +} // namespace cru::io diff --git a/include/cru/base/io/Resource.h b/include/cru/base/io/Resource.h new file mode 100644 index 00000000..1d5313a6 --- /dev/null +++ b/include/cru/base/io/Resource.h @@ -0,0 +1,8 @@ +#pragma once +#include "../Base.h" + +#include + +namespace cru::io { +std::filesystem::path CRU_BASE_API GetResourceDir(); +} diff --git a/include/cru/base/io/Stream.h b/include/cru/base/io/Stream.h new file mode 100644 index 00000000..e0b61627 --- /dev/null +++ b/include/cru/base/io/Stream.h @@ -0,0 +1,126 @@ +#pragma once + +#include "../Base.h" + +#include "../Exception.h" +#include "../String.h" + +#include + +namespace cru::io { +class CRU_BASE_API StreamOperationNotSupportedException : public Exception { + public: + explicit StreamOperationNotSupportedException(String operation); + + CRU_DEFAULT_DESTRUCTOR(StreamOperationNotSupportedException) + + public: + String GetOperation() const { return operation_; } + + public: + static void CheckSeek(bool seekable); + static void CheckRead(bool readable); + static void CheckWrite(bool writable); + + private: + String operation_; +}; + +class CRU_BASE_API StreamAlreadyClosedException : public Exception { + public: + StreamAlreadyClosedException(); + + CRU_DEFAULT_DESTRUCTOR(StreamAlreadyClosedException) + + static void Check(bool closed); +}; + +#define CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE \ + void Close() override { DoClose(); } + +#define CRU_STREAM_BEGIN_CLOSE \ + if (GetClosed()) return; \ + CloseGuard close_guard(this); + +/** + * All stream is thread-unsafe by default unless being documented. + */ +class CRU_BASE_API Stream : public Object { + protected: + struct SupportedOperations { + std::optional can_seek; + std::optional can_read; + std::optional can_write; + }; + + struct CloseGuard { + explicit CloseGuard(Stream* stream) : stream(stream) {} + ~CloseGuard() { stream->SetClosed(true); } + Stream* stream; + }; + + protected: + explicit Stream(SupportedOperations supported_operations = {}); + Stream(std::optional can_seek, std::optional can_read, + std::optional can_write); + + public: + enum class SeekOrigin { Current, Begin, End }; + + CRU_DELETE_COPY(Stream) + CRU_DELETE_MOVE(Stream) + + ~Stream() override = default; + + public: + bool CanSeek(); + Index Seek(Index offset, SeekOrigin origin = SeekOrigin::Current); + Index Tell(); + void Rewind(); + Index GetSize(); + + bool CanRead(); + Index Read(std::byte* buffer, Index offset, Index size); + Index Read(std::byte* buffer, Index size); + Index Read(char* buffer, Index offset, Index size); + Index Read(char* buffer, Index size); + + bool CanWrite(); + Index Write(const std::byte* buffer, Index offset, Index size); + Index Write(const std::byte* buffer, Index size); + Index Write(const char* buffer, Index offset, Index size); + Index Write(const char* buffer, Index size); + + void Flush(); + virtual void Close() = 0; + + virtual Buffer ReadToEnd(Index grow_size = 256); + + // Utf8 encoding. + String ReadToEndAsUtf8String(); + + protected: + virtual bool DoCanSeek(); + virtual bool DoCanRead(); + virtual bool DoCanWrite(); + virtual Index DoSeek(Index offset, SeekOrigin origin); + virtual Index DoTell(); + virtual void DoRewind(); + virtual Index DoGetSize(); + virtual Index DoRead(std::byte* buffer, Index offset, Index size); + virtual Index DoWrite(const std::byte* buffer, Index offset, Index size); + virtual void DoFlush(); + + void SetSupportedOperations(SupportedOperations supported_operations) { + supported_operations_ = std::move(supported_operations); + } + + bool GetClosed() { return closed_; } + void SetClosed(bool closed) { closed_ = closed; } + void CheckClosed() { StreamAlreadyClosedException::Check(closed_); } + + private: + std::optional supported_operations_; + bool closed_; +}; +} // namespace cru::io diff --git a/include/cru/base/log/Logger.h b/include/cru/base/log/Logger.h new file mode 100644 index 00000000..25735e14 --- /dev/null +++ b/include/cru/base/log/Logger.h @@ -0,0 +1,88 @@ +#pragma once +#include "../Base.h" + +#include "../Format.h" +#include "../String.h" +#include "../concurrent/ConcurrentQueue.h" + +#include +#include +#include +#include + +namespace cru::log { +enum class LogLevel { Debug, Info, Warn, Error }; + +struct CRU_BASE_API LogInfo { + LogInfo(LogLevel level, String tag, String message) + : level(level), tag(std::move(tag)), message(std::move(message)) {} + + CRU_DEFAULT_COPY(LogInfo) + CRU_DEFAULT_MOVE(LogInfo) + + ~LogInfo() = default; + + LogLevel level; + String tag; + String message; +}; + +struct CRU_BASE_API ILogTarget : virtual Interface { + // Write the string s. LogLevel is just a helper. It has no effect on the + // content to write. + virtual void Write(LogLevel level, StringView s) = 0; +}; + +class CRU_BASE_API Logger : public Object { + public: + static Logger* GetInstance(); + + public: + Logger(); + + CRU_DELETE_COPY(Logger) + CRU_DELETE_MOVE(Logger) + + ~Logger() override; + + public: + void AddLogTarget(std::unique_ptr source); + void RemoveLogTarget(ILogTarget* source); + + public: + void Log(LogLevel level, String tag, String message) { + Log(LogInfo(level, std::move(tag), std::move(message))); + } + void Log(LogInfo log_info); + + template + void FormatLog(LogLevel level, String tag, StringView format, + Args&&... args) { + Log(level, std::move(tag), Format(format, std::forward(args)...)); + } + + private: + concurrent::ConcurrentQueue log_queue_; + + std::mutex target_list_mutex_; + std::vector> target_list_; + + std::thread log_thread_; +}; +} // namespace cru::log + +#define CRU_LOG_DEBUG(...) \ + cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Debug, \ + kLogTag, __VA_ARGS__) + +#define CRU_LOG_INFO(...) \ + cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Info, \ + kLogTag, __VA_ARGS__) + +#define CRU_LOG_WARN(...) \ + cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Warn, \ + kLogTag, __VA_ARGS__) + +#define CRU_LOG_ERROR(...) \ + cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Error, \ + kLogTag, __VA_ARGS__) diff --git a/include/cru/base/log/StdioLogTarget.h b/include/cru/base/log/StdioLogTarget.h new file mode 100644 index 00000000..4123766b --- /dev/null +++ b/include/cru/base/log/StdioLogTarget.h @@ -0,0 +1,17 @@ +#pragma once +#include "Logger.h" + +namespace cru::log { +class StdioLogTarget : public Object, public virtual log::ILogTarget { + public: + explicit StdioLogTarget(); + + CRU_DELETE_COPY(StdioLogTarget) + CRU_DELETE_MOVE(StdioLogTarget) + + ~StdioLogTarget() override; + + public: + void Write(log::LogLevel level, StringView s) override; +}; +} // namespace cru::log diff --git a/include/cru/base/platform/Exception.h b/include/cru/base/platform/Exception.h new file mode 100644 index 00000000..74dd6ad4 --- /dev/null +++ b/include/cru/base/platform/Exception.h @@ -0,0 +1,12 @@ +#pragma once +#include "../Base.h" +#include "../Exception.h" + +namespace cru::platform { +class CRU_BASE_API PlatformException : public Exception { + public: + using Exception::Exception; // inherit constructors + + CRU_DEFAULT_DESTRUCTOR(PlatformException) +}; +} // namespace cru::platform diff --git a/include/cru/base/platform/osx/Convert.h b/include/cru/base/platform/osx/Convert.h new file mode 100644 index 00000000..395cbbae --- /dev/null +++ b/include/cru/base/platform/osx/Convert.h @@ -0,0 +1,18 @@ +#pragma once +#include "../../PreConfig.h" + +#ifndef CRU_PLATFORM_OSX +#error "This file can only be included on osx." +#endif + +#include "../../String.h" + +#include + +namespace cru::platform::osx { +CFStringRef Convert(const String& string); +String Convert(CFStringRef string); + +CFRange Convert(const Range& range); +Range Convert(const CFRange& range); +} // namespace cru::platform::osx diff --git a/include/cru/base/platform/osx/Exception.h b/include/cru/base/platform/osx/Exception.h new file mode 100644 index 00000000..5ab14ebd --- /dev/null +++ b/include/cru/base/platform/osx/Exception.h @@ -0,0 +1,15 @@ +#pragma once +#include "../../PreConfig.h" + +#ifndef CRU_PLATFORM_OSX +#error "This file can only be included on osx." +#endif + +#include "../Exception.h" + +namespace cru::platform::osx { +class OsxException : public PlatformException { + public: + using PlatformException::PlatformException; +}; +} // namespace cru::platform::osx diff --git a/include/cru/base/platform/unix/PosixSpawnSubProcess.h b/include/cru/base/platform/unix/PosixSpawnSubProcess.h new file mode 100644 index 00000000..ee4e912a --- /dev/null +++ b/include/cru/base/platform/unix/PosixSpawnSubProcess.h @@ -0,0 +1,50 @@ +#pragma once + +#include "../../PreConfig.h" + +#ifndef CRU_PLATFORM_UNIX +#error "This file can only be included on unix." +#endif + +#include "../../Base.h" +#include "../../SubProcess.h" +#include "../../io/AutoReadStream.h" + +#include "UnixFileStream.h" +#include "UnixPipe.h" + +#include + +namespace cru::platform::unix { +class PosixSpawnSubProcessImpl : public Object, + public virtual IPlatformSubProcessImpl { + CRU_DEFINE_CLASS_LOG_TAG(u"PosixSpawnSubProcess") + + public: + explicit PosixSpawnSubProcessImpl(); + ~PosixSpawnSubProcessImpl(); + + void PlatformCreateProcess(const SubProcessStartInfo& start_info) override; + SubProcessExitResult PlatformWaitForProcess() override; + void PlatformKillProcess() override; + + io::Stream* GetStdinStream() override; + io::Stream* GetStdoutStream() override; + io::Stream* GetStderrStream() override; + + private: + pid_t pid_; + int exit_code_; + + UnixPipe stdin_pipe_; + UnixPipe stdout_pipe_; + UnixPipe stderr_pipe_; + + std::unique_ptr stdin_stream_; + std::unique_ptr stdout_stream_; + std::unique_ptr stderr_stream_; + + std::unique_ptr stdout_buffer_stream_; + std::unique_ptr stderr_buffer_stream_; +}; +} // namespace cru::platform::unix diff --git a/include/cru/base/platform/unix/UnixFileStream.h b/include/cru/base/platform/unix/UnixFileStream.h new file mode 100644 index 00000000..8021f21a --- /dev/null +++ b/include/cru/base/platform/unix/UnixFileStream.h @@ -0,0 +1,39 @@ +#pragma once + +#include "../../PreConfig.h" + +#ifndef CRU_PLATFORM_UNIX +#error "This file can only be included on unix." +#endif + +#include "../../io/Stream.h" + +namespace cru::platform::unix { +class UnixFileStream : public io::Stream { + private: + static constexpr auto kLogTag = u"cru::platform::unix::UnixFileStream"; + + public: + UnixFileStream(const char* path, int oflag, mode_t mode = 0660); + UnixFileStream(int fd, bool can_seek, bool can_read, bool can_write, + bool auto_close); + ~UnixFileStream() override; + + public: + CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE + + int GetFileDescriptor() const { return file_descriptor_; } + + protected: + Index DoSeek(Index offset, SeekOrigin origin = SeekOrigin::Current) override; + Index DoRead(std::byte* buffer, Index offset, Index size) override; + Index DoWrite(const std::byte* buffer, Index offset, Index size) override; + + private: + void DoClose(); + + private: + int file_descriptor_; // -1 for no file descriptor + bool auto_close_; +}; +} // namespace cru::platform::unix diff --git a/include/cru/base/platform/unix/UnixPipe.h b/include/cru/base/platform/unix/UnixPipe.h new file mode 100644 index 00000000..cf35fb11 --- /dev/null +++ b/include/cru/base/platform/unix/UnixPipe.h @@ -0,0 +1,70 @@ +#pragma once + +#include "../../PreConfig.h" + +#ifndef CRU_PLATFORM_UNIX +#error "This file can only be included on unix." +#endif + +#include "../../Base.h" +#include "../../Bitmask.h" + +namespace cru::platform::unix { +namespace details { +struct UnixPipeFlagTag; +} +using UnixPipeFlag = Bitmask; +struct UnixPipeFlags { + constexpr static auto NonBlock = UnixPipeFlag::FromOffset(1); +}; + +/** + * @brief an unix pipe, commonly for communication of parent process and child + * process. + * + * There are two types of pipes sorted by its usage. For stdin, parent process + * SEND data to child process. For stdout and stderr, parent process RECEIVE + * data from child process. Each pipe has two ends, one for read and the other + * for write. But for send and receive, they are reversed. It is a little + * confused to consider which end should be used by parent and which end should + * be used by child. So this class help you make it clear. You specify SEND or + * RECEIVE, and this class give you a parent used end and a child used end. + * + * This class will only close the end used by parent when it is destructed. It + * is the user's duty to close the one used by child. + */ +class UnixPipe : public Object { + private: + constexpr static auto kLogTag = u"cru::platform::unix::UnixPipe"; + + public: + enum class Usage { + Send, + Receive, + }; + + explicit UnixPipe(Usage usage, bool auto_close, UnixPipeFlag flags = {}); + + CRU_DELETE_COPY(UnixPipe) + CRU_DELETE_MOVE(UnixPipe) + + ~UnixPipe(); + + /** + * @brief aka, the one used by parent process. + */ + int GetSelfFileDescriptor(); + + /** + * @brief aka, the one used by child process. + */ + int GetOtherFileDescriptor(); + + private: + Usage usage_; + bool auto_close_; + UnixPipeFlag flags_; + int read_fd_; + int write_fd_; +}; +} // namespace cru::platform::unix diff --git a/include/cru/base/platform/web/WebException.h b/include/cru/base/platform/web/WebException.h new file mode 100644 index 00000000..d98b8943 --- /dev/null +++ b/include/cru/base/platform/web/WebException.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../../PreConfig.h" + +#ifdef CRU_PLATFORM_EMSCRIPTEN + +#include "../Exception.h" + +namespace cru::platform::web { +class WebException : public PlatformException { + public: + using PlatformException::PlatformException; +}; +} // namespace cru::platform::web + +#endif diff --git a/include/cru/base/platform/win/ComAutoInit.h b/include/cru/base/platform/win/ComAutoInit.h new file mode 100644 index 00000000..569085c8 --- /dev/null +++ b/include/cru/base/platform/win/ComAutoInit.h @@ -0,0 +1,21 @@ +#pragma once + +#include "../../PreConfig.h" +#ifdef CRU_PLATFORM_WINDOWS + +#include "WinPreConfig.h" +#include "cru/base/Base.h" + +namespace cru::platform::win { +class CRU_BASE_API ComAutoInit { + public: + ComAutoInit(); + + CRU_DELETE_COPY(ComAutoInit) + CRU_DELETE_MOVE(ComAutoInit) + + ~ComAutoInit(); +}; +} // namespace cru::platform::win + +#endif diff --git a/include/cru/base/platform/win/DebugLogTarget.h b/include/cru/base/platform/win/DebugLogTarget.h new file mode 100644 index 00000000..8257f637 --- /dev/null +++ b/include/cru/base/platform/win/DebugLogTarget.h @@ -0,0 +1,25 @@ +#pragma once + +#include "../../PreConfig.h" +#ifdef CRU_PLATFORM_WINDOWS + +#include "WinPreConfig.h" + +#include "../../log/Logger.h" + +namespace cru::platform::win { + +class CRU_BASE_API WinDebugLogTarget : public ::cru::log::ILogTarget { + public: + WinDebugLogTarget() = default; + + CRU_DELETE_COPY(WinDebugLogTarget) + CRU_DELETE_MOVE(WinDebugLogTarget) + + ~WinDebugLogTarget() = default; + + void Write(::cru::log::LogLevel level, StringView s) override; +}; +} // namespace cru::platform::win + +#endif diff --git a/include/cru/base/platform/win/Exception.h b/include/cru/base/platform/win/Exception.h new file mode 100644 index 00000000..3e63b191 --- /dev/null +++ b/include/cru/base/platform/win/Exception.h @@ -0,0 +1,56 @@ +#pragma once +#include "../../PreConfig.h" +#ifdef CRU_PLATFORM_WINDOWS + +#include "WinPreConfig.h" + +#include "../Exception.h" + +#include +#include + +namespace cru::platform::win { +class CRU_BASE_API HResultError : public platform::PlatformException { + public: + explicit HResultError(HRESULT h_result); + explicit HResultError(HRESULT h_result, std::string_view message); + + CRU_DEFAULT_COPY(HResultError) + CRU_DEFAULT_MOVE(HResultError) + + ~HResultError() override = default; + + HRESULT GetHResult() const { return h_result_; } + + private: + HRESULT h_result_; +}; + +inline void ThrowIfFailed(const HRESULT h_result) { + if (FAILED(h_result)) throw HResultError(h_result); +} + +inline void ThrowIfFailed(const HRESULT h_result, std::string_view message) { + if (FAILED(h_result)) throw HResultError(h_result, message); +} + +class CRU_BASE_API Win32Error : public platform::PlatformException { + public: + // ::GetLastError is automatically called to get the error code. + // The same as Win32Error(::GetLastError(), message) + explicit Win32Error(String message); + Win32Error(DWORD error_code, String message); + + CRU_DEFAULT_COPY(Win32Error) + CRU_DEFAULT_MOVE(Win32Error) + + ~Win32Error() override = default; + + DWORD GetErrorCode() const { return error_code_; } + + private: + DWORD error_code_; +}; +} // namespace cru::platform::win + +#endif diff --git a/include/cru/base/platform/win/StreamConvert.h b/include/cru/base/platform/win/StreamConvert.h new file mode 100644 index 00000000..3499604a --- /dev/null +++ b/include/cru/base/platform/win/StreamConvert.h @@ -0,0 +1,14 @@ +#pragma once +#include "../../PreConfig.h" + +#ifdef CRU_PLATFORM_WINDOWS + +#include "../../io/Stream.h" + +#include + +namespace cru::platform::win { +CRU_BASE_API IStream* ConvertStreamToComStream(io::Stream* stream); +} + +#endif diff --git a/include/cru/base/platform/win/Win32FileStream.h b/include/cru/base/platform/win/Win32FileStream.h new file mode 100644 index 00000000..06656466 --- /dev/null +++ b/include/cru/base/platform/win/Win32FileStream.h @@ -0,0 +1,56 @@ +#pragma once + +#include "../../PreConfig.h" + +#ifdef CRU_PLATFORM_WINDOWS + +#include "../../String.h" +#include "../../io/OpenFileFlag.h" +#include "../../io/Stream.h" + +namespace cru::platform::win { +namespace details { +class Win32FileStreamPrivate; +} + +class CRU_BASE_API Win32FileStream : public io::Stream { + public: + Win32FileStream(String path, io::OpenFileFlag flags); + + CRU_DELETE_COPY(Win32FileStream) + CRU_DELETE_MOVE(Win32FileStream) + + ~Win32FileStream() override; + + public: + bool CanSeek() override; + Index Seek(Index offset, SeekOrigin origin = SeekOrigin::Current) override; + + bool CanRead() override; + Index Read(std::byte* buffer, Index offset, Index size) override; + using Stream::Read; + + bool CanWrite() override; + Index Write(const std::byte* buffer, Index offset, Index size) override; + using Stream::Write; + + void Close() override; + + String GetPath() const { return path_; } + io::OpenFileFlag GetOpenFileFlags() const { return flags_; } + + details::Win32FileStreamPrivate* GetPrivate_() { return p_; } + + private: + void CheckClosed(); + + private: + String path_; + io::OpenFileFlag flags_; + bool closed_ = false; + + details::Win32FileStreamPrivate* p_; +}; +} // namespace cru::platform::win + +#endif diff --git a/include/cru/base/platform/win/WinPreConfig.h b/include/cru/base/platform/win/WinPreConfig.h new file mode 100644 index 00000000..c2284df3 --- /dev/null +++ b/include/cru/base/platform/win/WinPreConfig.h @@ -0,0 +1,13 @@ +#pragma once +#include "../../PreConfig.h" +#ifdef CRU_PLATFORM_WINDOWS + +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN +#include +#undef CreateWindow +#undef DrawText +#undef CreateFont +#undef CreateEvent + +#endif diff --git a/include/cru/common/Base.h b/include/cru/common/Base.h deleted file mode 100644 index 8a6a7634..00000000 --- a/include/cru/common/Base.h +++ /dev/null @@ -1,112 +0,0 @@ -#pragma once -#include "PreConfig.h" // IWYU pragma: keep - -#include -#include -#include -#include - -#ifdef CRU_PLATFORM_WINDOWS -#ifdef CRU_BASE_EXPORT_API -#define CRU_BASE_API __declspec(dllexport) -#else -#define CRU_BASE_API __declspec(dllimport) -#endif -#else -#define CRU_BASE_API -#endif - -#define CRU_UNUSED(entity) static_cast(entity); - -#define CRU__CONCAT(a, b) a##b -#define CRU_MAKE_UNICODE_LITERAL(str) CRU__CONCAT(u, #str) - -#define CRU_DEFAULT_COPY(classname) \ - classname(const classname&) = default; \ - classname& operator=(const classname&) = default; - -#define CRU_DEFAULT_MOVE(classname) \ - classname(classname&&) = default; \ - classname& operator=(classname&&) = default; - -#define CRU_DELETE_COPY(classname) \ - classname(const classname&) = delete; \ - classname& operator=(const classname&) = delete; - -#define CRU_DELETE_MOVE(classname) \ - classname(classname&&) = delete; \ - classname& operator=(classname&&) = delete; - -#define CRU_DEFAULT_DESTRUCTOR(classname) ~classname() = default; - -#define CRU_DEFAULT_CONSTRUCTOR_DESTRUCTOR(classname) \ - classname() = default; \ - ~classname() = default; - -#define CRU_DEFINE_COMPARE_OPERATORS(classname) \ - inline bool operator==(const classname& left, const classname& right) { \ - return left.Compare(right) == 0; \ - } \ - \ - inline bool operator!=(const classname& left, const classname& right) { \ - return left.Compare(right) != 0; \ - } \ - \ - inline bool operator<(const classname& left, const classname& right) { \ - return left.Compare(right) < 0; \ - } \ - \ - inline bool operator<=(const classname& left, const classname& right) { \ - return left.Compare(right) <= 0; \ - } \ - \ - inline bool operator>(const classname& left, const classname& right) { \ - return left.Compare(right) > 0; \ - } \ - \ - inline bool operator>=(const classname& left, const classname& right) { \ - return left.Compare(right) >= 0; \ - } - -namespace cru { -class CRU_BASE_API Object { - public: - Object() = default; - CRU_DEFAULT_COPY(Object) - CRU_DEFAULT_MOVE(Object) - virtual ~Object() = default; -}; - -struct CRU_BASE_API Interface { - Interface() = default; - CRU_DELETE_COPY(Interface) - CRU_DELETE_MOVE(Interface) - virtual ~Interface() = default; -}; - -[[noreturn]] void CRU_BASE_API UnreachableCode(); - -using Index = std::ptrdiff_t; - -inline void Expects(bool condition) { assert(condition); } -inline void Ensures(bool condition) { assert(condition); } -template -inline void Expects(const std::shared_ptr& ptr) { - assert(ptr != nullptr); -} -template -inline void Ensures(const std::shared_ptr& ptr) { - assert(ptr != nullptr); -} - -// https://www.boost.org/doc/libs/1_54_0/doc/html/hash/reference.html#boost.hash_combine -template -inline void hash_combine(std::size_t& s, const T& v) { - std::hash h; - s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2); -} - -#define CRU_DEFINE_CLASS_LOG_TAG(tag) \ - private: \ - constexpr static const char16_t* kLogTag = tag; -} // namespace cru diff --git a/include/cru/common/Bitmask.h b/include/cru/common/Bitmask.h deleted file mode 100644 index 9b6b8957..00000000 --- a/include/cru/common/Bitmask.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include - -namespace cru { -template -struct Bitmask final { - using Underlying = TUnderlying; - - constexpr Bitmask() : value(0) {} - constexpr explicit Bitmask(TUnderlying value) : value(value) {} - - static constexpr Bitmask FromOffset(int offset) { - return Bitmask(static_cast(1u << offset)); - } - - constexpr bool Has(Bitmask rhs) const { return (value & rhs.value) != 0; } - - Bitmask operator|(Bitmask rhs) const { return Bitmask(value | rhs.value); } - Bitmask operator&(Bitmask rhs) const { return Bitmask(value & rhs.value); } - Bitmask operator^(Bitmask rhs) const { return Bitmask(value ^ rhs.value); } - Bitmask operator~() const { return Bitmask(~value); } - Bitmask& operator|=(Bitmask rhs) { - value |= rhs.value; - return *this; - } - Bitmask& operator&=(Bitmask rhs) { - value &= rhs.value; - return *this; - } - Bitmask& operator^=(Bitmask rhs) { - value ^= rhs.value; - return *this; - } - - bool operator==(Bitmask rhs) const { return this->value == rhs.value; } - bool operator!=(Bitmask rhs) const { return this->value != rhs.value; } - - explicit operator TUnderlying() const { return value; } - operator bool() const { return value != 0; } - - TUnderlying value; -}; -} // namespace cru - -namespace std { -template -struct hash> { - using Bitmask = cru::Bitmask; - - std::size_t operator()(Bitmask bitmask) const { - return std::hash{}(bitmask.value); - } -}; -} // namespace std diff --git a/include/cru/common/Buffer.h b/include/cru/common/Buffer.h deleted file mode 100644 index bc2e2a26..00000000 --- a/include/cru/common/Buffer.h +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once - -#include "Base.h" - -namespace cru { -class Buffer final { - friend void swap(Buffer& left, Buffer& right) noexcept; - - public: - Buffer(); - explicit Buffer(Index size); - - Buffer(const Buffer& other); - Buffer(Buffer&& other) noexcept; - - Buffer& operator=(const Buffer& other); - Buffer& operator=(Buffer&& other) noexcept; - - ~Buffer(); - - public: - Index GetBufferSize() const { return size_; } - Index GetUsedSize() const { return used_end_ - used_begin_; } - bool IsNull() const { return ptr_ == nullptr; } - bool IsUsedReachEnd() const { return used_end_ == size_; } - - Index GetFrontFree() const { return used_begin_; } - Index GetBackFree() const { return size_ - used_end_; } - - Index GetUsedBegin() const { return used_begin_; } - Index GetUsedEnd() const { return used_end_; } - - std::byte* GetPtr() { return GetPtrAt(0); } - const std::byte* GetPtr() const { return GetPtrAt(0); } - - std::byte* GetPtrAt(Index index) { return ptr_ + index; } - const std::byte* GetPtrAt(Index index) const { return ptr_ + index; } - - std::byte& GetRefAt(Index index) { return *GetPtrAt(index); } - const std::byte& GetRefAt(Index index) const { return *GetPtrAt(index); } - - std::byte* GetUsedBeginPtr() { return GetPtrAt(GetUsedBegin()); } - const std::byte* GetUsedBeginPtr() const { return GetPtrAt(GetUsedBegin()); } - std::byte* GetUsedEndPtr() { return GetPtrAt(GetUsedEnd()); } - const std::byte* GetUsedEndPtr() const { return GetPtrAt(GetUsedEnd()); } - - std::byte GetByteAt(Index index) const { return ptr_[index]; } - void SetByteAt(Index index, std::byte value) { ptr_[index] = value; } - - void AssignBytes(std::byte* src, Index src_size, bool use_memmove = false) { - return AssignBytes(0, src, 0, src_size, use_memmove); - } - void AssignBytes(Index dst_offset, std::byte* src, Index src_size, - bool use_memmove = false) { - return AssignBytes(dst_offset, src, 0, src_size, use_memmove); - } - void AssignBytes(Index dst_offset, std::byte* src, Index src_offset, - Index src_size, bool use_memmove = false); - - /** - * @brief Change the size of the buffer. - * - * Unless new size is the same as current size, the buffer is always released - * and a new one is allocated. If preserve_used is true, the used size and old - * data is copied to the new buffer. If new size is smaller than old used - * size, then exceeded data will be lost. - */ - void ResizeBuffer(Index new_size, bool preserve_used); - - /** - * @brief Append data to the front of used bytes and increase used size. - * @return The actual size of data saved. - * - * If there is no enough space left for new data, the rest space will be - * written and the size of it will be returned, leaving exceeded data not - * saved. - */ - Index PushFront(const std::byte* other, Index other_size, - bool use_memmove = false); - - bool PushBack(std::byte b); - - /** - * @brief Append data to the back of used bytes and increase used size. - * @return The actual size of data saved. - * - * If there is no enough space left for new data, the rest space will be - * written and the size of it will be returned, leaving exceeded data not - * saved. - */ - Index PushBack(const std::byte* other, Index other_size, - bool use_memmove = false); - - void PushBackCount(Index count); - - /** - * @brief Move forward the used-begin ptr. - * @return The actual size moved forward. - * - * If given size is bigger than current used size, the used size will be - * returned and set to 0. - */ - Index PopFront(Index size); - - /** - * @brief Pop front data of used bytes into another buffer. - * @return The actual size popped. - * - * If given size is bigger than current used size, then only current used size - * of bytes will be popped. If given size is smaller than current used size, - * then only given size of bytes will be popped. - */ - Index PopFront(std::byte* buffer, Index size, bool use_memmove = false); - - /** - * @brief Move backward the used-end ptr. - * @return The actual size moved backward. - * - * If given size is bigger than current used size, the used size will be - * returned and set to 0. - */ - Index PopEnd(Index size); - - /** - * @brief Pop back data of used bytes into another buffer. - * @return The actual size popped. - * - * If given size is bigger than current used size, then only current used size - * of bytes will be popped. If given size is smaller than current used size, - * then only given size of bytes will be popped. - */ - Index PopEnd(std::byte* buffer, Index size, bool use_memmove = false); - - operator std::byte*() { return GetPtr(); } - operator const std::byte*() const { return GetPtr(); } - - /** - * @brief Detach internal buffer and return it. - * @param size If not null, size of the buffer is written to it. - * @return The buffer pointer. May be nullptr. - * - * After detach, you are responsible to delete[] it. - */ - std::byte* Detach(Index* size = nullptr); - - private: - void Copy_(const Buffer& other); - void Move_(Buffer&& other) noexcept; - void Delete_() noexcept; - - void AssertValid(); - - private: - std::byte* ptr_; - Index size_; - Index used_begin_; - Index used_end_; -}; - -void swap(Buffer& left, Buffer& right) noexcept; -} // namespace cru diff --git a/include/cru/common/ClonablePtr.h b/include/cru/common/ClonablePtr.h deleted file mode 100644 index a2a88758..00000000 --- a/include/cru/common/ClonablePtr.h +++ /dev/null @@ -1,216 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace cru { -template -class ClonablePtr { - template - friend class ClonablePtr; - - public: - using element_type = typename std::unique_ptr::element_type; - using pointer = typename std::unique_ptr::pointer; - - ClonablePtr() = default; - ClonablePtr(std::nullptr_t) noexcept : ptr_(nullptr) {} - explicit ClonablePtr(pointer p) noexcept : ptr_(p) {} - ClonablePtr(std::unique_ptr&& p) noexcept - : ptr_(std::move(p)) {} - template ::pointer, pointer>, - int> = 0> - ClonablePtr(std::unique_ptr&& p) : ptr_(std::move(p)) {} - ClonablePtr(const ClonablePtr& other) : ptr_(other.ptr_->Clone()) {} - ClonablePtr(ClonablePtr&& other) = default; - template ::pointer, pointer>, - int> = 0> - ClonablePtr(const ClonablePtr& other) : ptr_(other.ptr_->Clone()) {} - template ::pointer, pointer>, - int> = 0> - ClonablePtr(ClonablePtr&& other) noexcept : ptr_(std::move(other.ptr_)) {} - ClonablePtr& operator=(std::nullptr_t) noexcept { - ptr_ = nullptr; - return *this; - } - ClonablePtr& operator=(std::unique_ptr&& other) noexcept { - ptr_ = std::move(other); - return *this; - } - template ::pointer, pointer>, - int> = 0> - ClonablePtr& operator=(std::unique_ptr&& p) noexcept { - ptr_ = std::move(p); - return *this; - } - ClonablePtr& operator=(const ClonablePtr& other) { - if (this != &other) { - ptr_ = std::unique_ptr(other.ptr_->Clone()); - } - return *this; - } - ClonablePtr& operator=(ClonablePtr&& other) = default; - template ::pointer, pointer>, - int> = 0> - ClonablePtr& operator=(const ClonablePtr& other) noexcept { - if (this != &other) { - ptr_ = std::unique_ptr(other.ptr_->Clone()); - } - return *this; - } - template ::pointer, pointer>, - int> = 0> - ClonablePtr& operator=(ClonablePtr&& other) noexcept { - ptr_ = std::move(other.ptr_); - } - - ~ClonablePtr() = default; - - public: - pointer release() noexcept { return ptr_.release(); } - void reset(pointer p = pointer()) noexcept { ptr_.reset(p); } - void swap(ClonablePtr& other) noexcept { ptr_.swap(other.ptr_); } - - public: - pointer get() const noexcept { return ptr_.get(); } - - operator bool() const noexcept { return ptr_ != nullptr; } - - element_type& operator*() const noexcept { return *ptr_; } - pointer operator->() const noexcept { return ptr_.get(); } - - int Compare(const ClonablePtr& other) const noexcept { - if (ptr_ == other.ptr_) { - return 0; - } else if (ptr_ < other.ptr_) { - return -1; - } else { - return 1; - } - } - - int Compare(nullptr_t) const noexcept { return ptr_ ? 1 : 0; } - - private: - std::unique_ptr ptr_; -}; - -template -void swap(ClonablePtr& left, ClonablePtr& right) noexcept { - left.swap(right); -} - -template -bool operator==(const ClonablePtr& left, const ClonablePtr& right) { - return left.Compare(right) == 0; -} - -template -bool operator!=(const ClonablePtr& left, const ClonablePtr& right) { - return left.Compare(right) != 0; -} - -template -bool operator<(const ClonablePtr& left, const ClonablePtr& right) { - return left.Compare(right) < 0; -} - -template -bool operator<=(const ClonablePtr& left, const ClonablePtr& right) { - return left.Compare(right) <= 0; -} - -template -bool operator>(const ClonablePtr& left, const ClonablePtr& right) { - return left.Compare(right) > 0; -} - -template -bool operator>=(const ClonablePtr& left, const ClonablePtr& right) { - return left.Compare(right) >= 0; -} - -template -bool operator==(const ClonablePtr& left, std::nullptr_t) { - return left.Compare(nullptr) == 0; -} - -template -bool operator!=(const ClonablePtr& left, std::nullptr_t) { - return left.Compare(nullptr) != 0; -} - -template -bool operator<(const ClonablePtr& left, std::nullptr_t) { - return left.Compare(nullptr) < 0; -} - -template -bool operator<=(const ClonablePtr& left, std::nullptr_t) { - return left.Compare(nullptr) <= 0; -} - -template -bool operator>(const ClonablePtr& left, std::nullptr_t) { - return left.Compare(nullptr) > 0; -} - -template -bool operator>=(const ClonablePtr& left, std::nullptr_t) { - return left.Compare(nullptr) >= 0; -} - -template -bool operator==(std::nullptr_t, const ClonablePtr& right) { - return right.Compare(nullptr) == 0; -} - -template -bool operator!=(std::nullptr_t, const ClonablePtr& right) { - return right.Compare(nullptr) != 0; -} - -template -bool operator<(std::nullptr_t, const ClonablePtr& right) { - return right.Compare(nullptr) > 0; -} - -template -bool operator<=(std::nullptr_t, const ClonablePtr& right) { - return right.Compare(nullptr) >= 0; -} - -template -bool operator>(std::nullptr_t, const ClonablePtr& right) { - return right.Compare(nullptr) < 0; -} - -template -bool operator>=(std::nullptr_t, const ClonablePtr& right) { - return right.Compare(nullptr) <= 0; -} - -} // namespace cru - -namespace std { -template -struct hash> { - std::size_t operator()(const cru::ClonablePtr& p) const { - return std::hash::pointer>(p.get()); - } -}; -} // namespace std diff --git a/include/cru/common/Event.h b/include/cru/common/Event.h deleted file mode 100644 index 18d2c570..00000000 --- a/include/cru/common/Event.h +++ /dev/null @@ -1,281 +0,0 @@ -#pragma once -#include "Base.h" - -#include "SelfResolvable.h" - -#include -#include -#include -#include -#include -#include - -namespace cru { -class EventRevoker; - -namespace details { -template -inline constexpr bool always_false_v = false; - -// Base class of all Event. -// It erases event args types and provides a -// unified form to create event revoker and -// revoke(remove) handler. -class EventBase : public SelfResolvable { - friend EventRevoker; - - protected: - using EventHandlerToken = long; - - EventBase() {} - CRU_DELETE_COPY(EventBase) - CRU_DEFAULT_MOVE(EventBase) - virtual ~EventBase() = default; - - // Remove the handler with the given token. If the token - // corresponds to no handler (which might have be revoked - // before), then nothing will be done. - virtual void RemoveHandler(EventHandlerToken token) = 0; - - // Create a revoker with the given token. - inline EventRevoker CreateRevoker(EventHandlerToken token); -}; -} // namespace details - -// A non-copyable and movable event revoker. -// Call function call operator to revoke the handler. -class EventRevoker { - friend details::EventBase; - - private: - EventRevoker(ObjectResolver&& resolver, - details::EventBase::EventHandlerToken token) - : resolver_(std::move(resolver)), token_(token) {} - - public: - EventRevoker(const EventRevoker& other) = default; - EventRevoker(EventRevoker&& other) = default; - EventRevoker& operator=(const EventRevoker& other) = default; - EventRevoker& operator=(EventRevoker&& other) = default; - ~EventRevoker() = default; - - // Revoke the registered handler. If the event has already - // been destroyed, then nothing will be done. If one of the - // copies calls this, then other copies's calls will have no - // effect. (They have the same token.) - void operator()() const { - if (const auto event = resolver_.Resolve()) { - event->RemoveHandler(token_); - } - } - - private: - ObjectResolver resolver_; - details::EventBase::EventHandlerToken token_; -}; - -inline EventRevoker details::EventBase::CreateRevoker(EventHandlerToken token) { - return EventRevoker(CreateResolver(), token); -} - -// int -> int -// Point -> const Point& -// int& -> int& -template -using DeducedEventArgs = std::conditional_t< - std::is_lvalue_reference_v, TRaw, - std::conditional_t, TRaw, const TRaw&>>; - -struct IBaseEvent { - protected: - IBaseEvent() = default; - CRU_DELETE_COPY(IBaseEvent) - CRU_DEFAULT_MOVE(IBaseEvent) - ~IBaseEvent() = default; // Note that user can't destroy a Event via IEvent. - // So destructor should be protected. - - using SpyOnlyHandler = std::function; - - public: - virtual EventRevoker AddSpyOnlyHandler(SpyOnlyHandler handler) = 0; -}; - -// Provides an interface of event. -// IEvent only allow to add handler but not to raise the event. You may -// want to create an Event object and expose IEvent only so users won't -// be able to emit the event. -template -struct IEvent : virtual IBaseEvent { - public: - using EventArgs = DeducedEventArgs; - using EventHandler = std::function; - using ShortCircuitHandler = std::function; - - protected: - IEvent() = default; - CRU_DELETE_COPY(IEvent) - CRU_DEFAULT_MOVE(IEvent) - ~IEvent() = default; // Note that user can't destroy a Event via IEvent. So - // destructor should be protected. - - public: - virtual EventRevoker AddHandler(EventHandler handler) = 0; - virtual EventRevoker AddShortCircuitHandler(ShortCircuitHandler handler) = 0; - virtual EventRevoker PrependShortCircuitHandler( - ShortCircuitHandler handler) = 0; -}; - -// A non-copyable non-movable Event class. -// It stores a list of event handlers. -template -class Event : public details::EventBase, public IEvent { - using typename IEvent::EventArgs; - - using typename IBaseEvent::SpyOnlyHandler; - using typename IEvent::EventHandler; - using typename IEvent::ShortCircuitHandler; - - private: - struct HandlerData { - HandlerData(EventHandlerToken token, ShortCircuitHandler handler) - : token(token), handler(std::move(handler)) {} - EventHandlerToken token; - ShortCircuitHandler handler; - }; - - public: - Event() = default; - CRU_DELETE_COPY(Event) - CRU_DEFAULT_MOVE(Event) - ~Event() = default; - - EventRevoker AddSpyOnlyHandler(SpyOnlyHandler handler) override { - return AddShortCircuitHandler([handler = std::move(handler)](EventArgs) { - handler(); - return false; - }); - } - - EventRevoker AddHandler(EventHandler handler) override { - return AddShortCircuitHandler( - [handler = std::move(handler)](EventArgs args) { - handler(args); - return false; - }); - } - - // Handler return true to short circuit following handlers. - EventRevoker AddShortCircuitHandler(ShortCircuitHandler handler) override { - const auto token = current_token_++; - this->handler_data_list_.emplace_back(token, std::move(handler)); - return CreateRevoker(token); - } - - // Handler return true to short circuit following handlers. - EventRevoker PrependShortCircuitHandler( - ShortCircuitHandler handler) override { - const auto token = current_token_++; - this->handler_data_list_.emplace(this->handler_data_list_.cbegin(), token, - std::move(handler)); - return CreateRevoker(token); - } - - // This method will make a copy of all handlers. Because user might delete a - // handler in a handler, which may lead to seg fault as the handler is - // deleted while being executed. Thanks to this behavior, all handlers will - // be taken a snapshot when Raise is called, so even if you delete a handler - // during this period, all handlers in the snapshot will be executed. - void Raise(EventArgs args) { - std::vector handlers; - handlers.reserve(this->handler_data_list_.size()); - for (const auto& data : this->handler_data_list_) { - handlers.push_back(data.handler); - } - for (const auto& handler : handlers) { - auto short_circuit = handler(args); - if (short_circuit) return; - } - } - - protected: - void RemoveHandler(EventHandlerToken token) override { - const auto find_result = std::find_if( - this->handler_data_list_.cbegin(), this->handler_data_list_.cend(), - [token](const HandlerData& data) { return data.token == token; }); - if (find_result != this->handler_data_list_.cend()) { - this->handler_data_list_.erase(find_result); - } - } - - private: - std::vector handler_data_list_; - EventHandlerToken current_token_ = 0; -}; - -namespace details { -struct EventRevokerDestroyer { - void operator()(EventRevoker* p) { - (*p)(); - delete p; - } -}; -} // namespace details - -// A guard class for event revoker. Automatically revoke it when destroyed. -class EventRevokerGuard { - public: - EventRevokerGuard() = default; - explicit EventRevokerGuard(EventRevoker&& revoker) - : revoker_(new EventRevoker(std::move(revoker))) {} - EventRevokerGuard(const EventRevokerGuard& other) = delete; - EventRevokerGuard(EventRevokerGuard&& other) = default; - EventRevokerGuard& operator=(const EventRevokerGuard& other) = delete; - EventRevokerGuard& operator=(EventRevokerGuard&& other) = default; - ~EventRevokerGuard() = default; - - EventRevoker Get() { - // revoker is only null when this is moved - // you shouldn't use a moved instance - assert(revoker_); - return *revoker_; - } - - EventRevoker Release() { return std::move(*revoker_.release()); } - - void Reset() { revoker_.reset(); } - - void Reset(EventRevoker&& revoker) { - revoker_.reset(new EventRevoker(std::move(revoker))); - } - - private: - std::unique_ptr revoker_; -}; - -class EventRevokerListGuard { - public: - EventRevokerListGuard() = default; - EventRevokerListGuard(const EventRevokerListGuard& other) = delete; - EventRevokerListGuard(EventRevokerListGuard&& other) = default; - EventRevokerListGuard& operator=(const EventRevokerListGuard& other) = delete; - EventRevokerListGuard& operator=(EventRevokerListGuard&& other) = default; - ~EventRevokerListGuard() = default; - - public: - void Add(EventRevoker&& revoker) { - event_revoker_guard_list_.push_back(EventRevokerGuard(std::move(revoker))); - } - - EventRevokerListGuard& operator+=(EventRevoker&& revoker) { - this->Add(std::move(revoker)); - return *this; - } - - void Clear() { event_revoker_guard_list_.clear(); } - - bool IsEmpty() const { return event_revoker_guard_list_.empty(); } - - private: - std::vector event_revoker_guard_list_; -}; -} // namespace cru diff --git a/include/cru/common/Event2.h b/include/cru/common/Event2.h deleted file mode 100644 index 62fb366d..00000000 --- a/include/cru/common/Event2.h +++ /dev/null @@ -1,200 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include - -namespace cru { -class Event2Base { - public: - virtual ~Event2Base() = default; - - virtual void RevokeHandler(int token_value) = 0; -}; - -template -class EventContext { - public: - EventContext() : argument_(), result_() {} - explicit EventContext(TArgument argument) - : argument_(std::move(argument)), result_() {} - EventContext(TArgument argument, TResult result) - : argument_(std::move(argument)), result_(std::move(result)) {} - - TArgument& GetArgument() { return argument_; } - const TArgument& GetArgument() const { return argument_; } - - TResult& GetResult() { return result_; } - const TResult& GetResult() const { return result_; } - void SetResult(const TResult& result) { result_ = result; } - void SetResult(TResult&& result) { result_ = std::move(result); } - TResult TakeResult() { return std::move(result_); } - - bool GetStopHandling() const { return stop_handling_; } - void SetStopHandling(bool stop = true) { stop_handling_ = stop; } - - private: - TArgument argument_; - TResult result_; - bool stop_handling_ = false; -}; - -template -class Event2; - -template -constexpr bool is_event2_v = false; - -template -constexpr bool is_event2_v> = true; - -class EventHandlerToken { - public: - EventHandlerToken(ObjectResolver event_resolver, int token_value) - : event_resolver_(std::move(event_resolver)), token_value_(token_value) {} - - ObjectResolver GetEventResolver() const { - return event_resolver_; - } - int GetTokenValue() const { return token_value_; } - inline void RevokeHandler() const; - - private: - ObjectResolver event_resolver_; - int token_value_; -}; - -namespace details { -struct Event2BehaviorFlagTag {}; -} // namespace details -using Event2BehaviorFlag = Bitmask; - -struct Event2BehaviorFlags { - /** - * @brief Make a copy of handler list before invoking handlers. So the event - * object or its owner can be destroyed during running handlers. - */ - static constexpr Event2BehaviorFlag CopyHandlers = - Event2BehaviorFlag::FromOffset(1); -}; - -template -class Event2 : public Event2Base, - public SelfResolvable> { - public: - using HandlerToken = EventHandlerToken; - using Context = EventContext; - using Handler = std::function; - using SpyOnlyHandler = std::function; - - template - static std::enable_if_t, Handler> WrapAsHandler( - TFunc&& handler) { - return Handler([h = std::forward(handler)](Context*) { h(); }); - } - - template - static std::enable_if_t, Handler> - WrapAsHandler(TFunc&& handler) { - return Handler(std::forward(handler)); - } - - private: - struct HandlerData { - int token_value; - Handler handler; - }; - - public: - explicit Event2(Event2BehaviorFlag flags = {}) : flags_(flags) {} - Event2(const Event2&) = delete; - Event2(Event2&&) = delete; - Event2& operator=(const Event2&) = delete; - Event2& operator=(Event2&&) = delete; - ~Event2() override = default; - - public: - template - HandlerToken AddHandler(TFunc&& handler) { - auto token = this->current_token_value_++; - auto real_handler = WrapAsHandler(std::forward(handler)); - HandlerData handler_data{token, std::move(real_handler)}; - this->handlers_.push_back(std::move(handler_data)); - return HandlerToken(this->CreateResolver(), token); - } - - void RevokeHandler(int token_value) override { - auto iter = this->handlers_.cbegin(); - auto end = this->handlers_.cend(); - for (; iter != end; ++iter) { - if (iter->token_value == token_value) { - this->handlers_.erase(iter); - break; - } - } - } - - void RevokeHandler(const HandlerToken& token) { - return RevokeHandler(token.GetTokenValue()); - } - - TResult Raise() { - Context context; - RunInContext(&context); - return context.TakeResult(); - } - - TResult Raise(TArgument argument) { - Context context(std::move(argument)); - RunInContext(&context); - return context.TakeResult(); - } - - TResult Raise(TArgument argument, TResult result) { - Context context(std::move(argument), std::move(result)); - RunInContext(&context); - return context.TakeResult(); - } - - private: - void RunInContext(Context* context) { - if (this->flags_ & Event2BehaviorFlags::CopyHandlers) { - std::vector handlers_copy; - for (const auto& handler : this->handlers_) { - handlers_copy.push_back(handler.handler); - } - for (const auto& handler : handlers_copy) { - if (context->GetStopHandling()) { - break; - } - handler(context); - } - } else { - for (const auto& handler : this->handlers_) { - if (context->GetStopHandling()) { - break; - } - handler.handler(context); - } - } - } - - private: - int current_token_value_ = 1; - std::vector handlers_; - Event2BehaviorFlag flags_; -}; - -inline void EventHandlerToken::RevokeHandler() const { - auto event = this->event_resolver_.Resolve(); - if (event) { - event->RevokeHandler(this->token_value_); - } -} -} // namespace cru diff --git a/include/cru/common/Exception.h b/include/cru/common/Exception.h deleted file mode 100644 index 609fd2c9..00000000 --- a/include/cru/common/Exception.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#include "String.h" - -#include -#include - -namespace cru { -#ifdef _MSC_VER -#pragma warning(disable : 4275) -#endif -class CRU_BASE_API Exception : public std::exception { - public: - explicit Exception(String message = {}, - std::unique_ptr inner = nullptr); - - ~Exception() override; - - public: - String GetMessage() const { return message_; } - - std::exception* GetInner() const noexcept { return inner_.get(); } - - const char* what() const noexcept override; - - protected: - void SetMessage(String message) { message_ = std::move(message); } - - void AppendMessage(StringView additional_message); - void AppendMessage(std::optional additional_message); - - private: - String message_; - mutable std::string utf8_message_; - std::unique_ptr inner_; -}; - -class CRU_BASE_API TextEncodeException : public Exception { - public: - using Exception::Exception; -}; - -class ErrnoException : public Exception { - public: - /** - * @brief will retrieve errno automatically. - */ - explicit ErrnoException(String message = {}); - ErrnoException(String message, int errno_code); - - CRU_DELETE_COPY(ErrnoException) - CRU_DELETE_MOVE(ErrnoException) - - ~ErrnoException() override = default; - - int GetErrnoCode() const { return errno_code_; } - - private: - int errno_code_; -}; -} // namespace cru diff --git a/include/cru/common/Format.h b/include/cru/common/Format.h deleted file mode 100644 index d5c5ed99..00000000 --- a/include/cru/common/Format.h +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once - -#include "Exception.h" -#include "String.h" - -#include -#include -#include -#include - -namespace cru { -inline String ToString(bool value) { - return value ? String(u"true") : String(u"false"); -} - -template -inline constexpr std::nullptr_t kPrintfFormatSpecifierOfType = nullptr; - -#define CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(type, specifier) \ - template <> \ - inline constexpr const char* kPrintfFormatSpecifierOfType = specifier; - -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed char, "%c") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned char, "%c") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed short, "%hd") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned short, "%hu") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed int, "%d") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned int, "%u") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed long, "%ld") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned long, "%lu") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed long long, "%lld") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned long long, "%llu") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(float, "%f") -CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(double, "%f") - -#undef CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE - -template -std::enable_if_t< - !std::is_null_pointer_v)>, String> -ToString(T value) { - auto size = std::snprintf(nullptr, 0, kPrintfFormatSpecifierOfType, value); - assert(size > 0); - std::vector buffer(size + 1); - size = std::snprintf(buffer.data(), size + 1, kPrintfFormatSpecifierOfType, - value); - assert(size > 0); - return String::FromUtf8(buffer.data(), size); -} - -template -String ToString(const T& value, StringView option) { - CRU_UNUSED(option) - return ToString(value); -} - -inline String ToString(String value) { return value; } - -namespace details { -enum class FormatTokenType { PlaceHolder, Text }; -enum class FormatPlaceHolderType { None, Positioned, Named }; - -struct FormatToken { - static FormatToken Text() { - return FormatToken{FormatTokenType::Text, {}, {}, 0, {}, {}}; - } - - static FormatToken NonePlaceHolder(String option) { - return FormatToken(FormatTokenType::PlaceHolder, {}, - FormatPlaceHolderType::None, 0, {}, std::move(option)); - } - - static FormatToken PositionedPlaceHolder(int position, String option) { - return FormatToken(FormatTokenType::PlaceHolder, {}, - FormatPlaceHolderType::Positioned, position, {}, - std::move(option)); - } - - static FormatToken NamedPlaceHolder(String name, String option) { - return FormatToken(FormatTokenType::PlaceHolder, {}, - FormatPlaceHolderType::Named, 0, std::move(name), - std::move(option)); - } - - FormatToken(FormatTokenType type, String data, - FormatPlaceHolderType place_holder_type, - int place_holder_position, String place_holder_name, - String place_holder_option) - : type(type), - data(std::move(data)), - place_holder_type(place_holder_type), - place_holder_position(place_holder_position), - place_holder_name(std::move(place_holder_name)), - place_holder_option(std::move(place_holder_option)) {} - - CRU_DEFAULT_COPY(FormatToken) - CRU_DEFAULT_MOVE(FormatToken) - - CRU_DEFAULT_DESTRUCTOR(FormatToken) - - FormatTokenType type; - String data; - FormatPlaceHolderType place_holder_type; - int place_holder_position; - String place_holder_name; - String place_holder_option; -}; - -std::vector CRU_BASE_API ParseToFormatTokenList(StringView str); - -void CRU_BASE_API FormatAppendFromFormatTokenList( - String& current, const std::vector& format_token_list, - Index index); - -template -void FormatAppendFromFormatTokenList( - String& current, const std::vector& format_token_list, - Index index, TA&& args0, T&&... args) { - for (Index i = index; i < static_cast(format_token_list.size()); i++) { - const auto& token = format_token_list[i]; - if (token.type == FormatTokenType::PlaceHolder) { - if (token.place_holder_type == FormatPlaceHolderType::None) { - current += ToString(std::forward(args0), token.place_holder_option); - FormatAppendFromFormatTokenList(current, format_token_list, i + 1, - std::forward(args)...); - - return; - } else { - throw Exception( - u"Currently do not support positional or named place holder."); - } - } else { - current += token.data; - } - } -} -} // namespace details - -template -String Format(StringView format, T&&... args) { - String result; - - details::FormatAppendFromFormatTokenList( - result, details::ParseToFormatTokenList(format), 0, - std::forward(args)...); - - return result; -} - -template -String String::Format(T&&... args) const { - return cru::Format(*this, std::forward(args)...); -} -} // namespace cru diff --git a/include/cru/common/Guard.h b/include/cru/common/Guard.h deleted file mode 100644 index 5a9f9c5d..00000000 --- a/include/cru/common/Guard.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -namespace cru { -struct Guard { - using ExitFunc = std::function; - - Guard() = default; - explicit Guard(const ExitFunc& f) : on_exit(f) {} - explicit Guard(ExitFunc&& f) : on_exit(std::move(f)) {} - Guard(const Guard&) = delete; - Guard(Guard&&) = default; - Guard& operator=(const Guard&) = delete; - Guard& operator=(Guard&&) = default; - ~Guard() { - if (on_exit) { - on_exit(); - } - } - - void Drop() { on_exit = {}; } - - ExitFunc on_exit; -}; -} // namespace cru diff --git a/include/cru/common/HandlerRegistry.h b/include/cru/common/HandlerRegistry.h deleted file mode 100644 index e405d1fd..00000000 --- a/include/cru/common/HandlerRegistry.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once -#include "Base.h" - -#include -#include -#include -#include - -namespace cru { - -template -class HandlerRegistryIterator { - public: - using RawIterator = - typename std::vector>>::const_iterator; - - explicit HandlerRegistryIterator(RawIterator raw) : raw_(std::move(raw)) {} - - CRU_DELETE_COPY(HandlerRegistryIterator) - CRU_DELETE_MOVE(HandlerRegistryIterator) - - ~HandlerRegistryIterator() = default; - - const std::function& operator*() const { return raw_->second; } - const std::function* operator->() const { return &raw_->second; } - - HandlerRegistryIterator& operator++() { - ++raw_; - return *this; - } - - HandlerRegistryIterator operator++(int) { - auto c = *this; - this->operator++(); - return c; - } - - bool operator==(const HandlerRegistryIterator& other) const { - return this->raw_ == other.raw_; - } - - bool operator!=(const HandlerRegistryIterator& other) const { - return !this->operator==(other); - } - - private: - RawIterator raw_; -}; - -template -class HandlerRegistry final { - public: - HandlerRegistry() = default; - CRU_DEFAULT_COPY(HandlerRegistry) - CRU_DEFAULT_MOVE(HandlerRegistry) - ~HandlerRegistry() = default; - - public: - int AddHandler(std::function handler) { - auto id = current_id_++; - handler_list_.push_back({id, std::move(handler)}); - return id; - } - - void RemoveHandler(int id) { - auto result = std::find_if(handler_list_.cbegin(), handler_list_.cend(), - [id](const std::pair>& d) { - return d.first == id; - }); - if (result != handler_list_.cend()) { - handler_list_.erase(result); - } - } - - HandlerRegistryIterator begin() const { - return HandlerRegistryIterator(handler_list_.begin()); - } - - HandlerRegistryIterator end() const { - return HandlerRegistryIterator(handler_list_.end()); - } - - private: - int current_id_ = 1; - std::vector>> handler_list_; -}; -} // namespace cru diff --git a/include/cru/common/PreConfig.h b/include/cru/common/PreConfig.h deleted file mode 100644 index 3f26c589..00000000 --- a/include/cru/common/PreConfig.h +++ /dev/null @@ -1,18 +0,0 @@ -// IWYU pragma: always_keep - -#pragma once - -#ifdef _MSC_VER -// disable the unnecessary warning about multi-inheritance -#pragma warning(disable : 4250) -// disable dll export template issue warning -#pragma warning(disable : 4251) -#endif - -#ifdef CRU_PLATFORM_WINDOWS -#define _CRT_SECURE_NO_WARNINGS -#endif - -#if defined(CRU_PLATFORM_OSX) || defined(CRU_PLATFORM_LINUX) -#define CRU_PLATFORM_UNIX -#endif diff --git a/include/cru/common/PropertyTree.h b/include/cru/common/PropertyTree.h deleted file mode 100644 index 54e185b9..00000000 --- a/include/cru/common/PropertyTree.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include "Base.h" -#include "String.h" - -#include - -namespace cru { -class PropertyTree; - -class CRU_BASE_API PropertySubTreeRef { - public: - static String CombineKey(StringView left, StringView right); - - explicit PropertySubTreeRef(PropertyTree* tree, String path = {}); - - CRU_DEFAULT_COPY(PropertySubTreeRef); - CRU_DEFAULT_MOVE(PropertySubTreeRef); - - CRU_DEFAULT_DESTRUCTOR(PropertySubTreeRef); - - public: - PropertyTree* GetTree() const { return tree_; } - - String GetPath() const { return path_; } - void SetPath(String path) { path_ = std::move(path); } - - PropertySubTreeRef GetParent() const; - PropertySubTreeRef GetChild(const String& key) const; - - String GetValue(const String& key) const; - void SetValue(const String& key, String value); - void DeleteValue(const String& key); - - private: - PropertyTree* tree_; - String path_; -}; - -class CRU_BASE_API PropertyTree { - public: - static String CombineKey(StringView left, StringView right); - - PropertyTree() = default; - explicit PropertyTree(std::unordered_map values); - - CRU_DELETE_COPY(PropertyTree); - CRU_DELETE_MOVE(PropertyTree); - - CRU_DEFAULT_DESTRUCTOR(PropertyTree); - - public: - String GetValue(const String& key) const; - void SetValue(const String& key, String value); - void DeleteValue(const String& key); - - PropertySubTreeRef GetSubTreeRef(const String& path); - - private: - std::unordered_map values_; -}; - -} // namespace cru diff --git a/include/cru/common/Range.h b/include/cru/common/Range.h deleted file mode 100644 index edc2ec55..00000000 --- a/include/cru/common/Range.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include "Base.h" - -namespace cru { -struct Range final { - constexpr static Range FromTwoSides(Index start, Index end) { - return Range(start, end - start); - } - - constexpr static Range FromTwoSides(Index start, Index end, Index offset) { - return Range(start + offset, end - start); - } - - constexpr Range() = default; - constexpr Range(const Index position, const Index count = 0) - : position(position), count(count) {} - - Index GetStart() const { return position; } - Index GetEnd() const { return position + count; } - - void ChangeEnd(Index new_end) { count = new_end - position; } - - Range Normalize() const { - auto result = *this; - if (result.count < 0) { - result.position += result.count; - result.count = -result.count; - } - return result; - } - - Range CoerceInto(Index min, Index max) const { - auto coerce = [min, max](Index index) { - return index > max ? max : (index < min ? min : index); - }; - return Range::FromTwoSides(coerce(GetStart()), coerce(GetEnd())); - } - - Index position = 0; - Index count = 0; -}; -} // namespace cru diff --git a/include/cru/common/SelfResolvable.h b/include/cru/common/SelfResolvable.h deleted file mode 100644 index 84fa54f6..00000000 --- a/include/cru/common/SelfResolvable.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace cru { -template -class SelfResolvable; - -template -class ObjectResolver { - friend SelfResolvable; - template - friend class ObjectResolver; - - private: - template - using Accessor_ = std::function&)>; - using ThisAccessor_ = Accessor_; - - explicit ObjectResolver(T* o) - : shared_object_ptr_(new void*(o)), - accessor_([](const std::shared_ptr& ptr) { - return static_cast(*ptr); - }) {} - explicit ObjectResolver(std::shared_ptr ptr, ThisAccessor_ accessor) - : shared_object_ptr_(std::move(ptr)), accessor_(std::move(accessor)) {} - - template - static ThisAccessor_ CreateAccessor(Accessor_ parent_accessor) { - return [parent_accessor = - std::move(parent_accessor)](const std::shared_ptr& ptr) { - return static_cast(parent_accessor(ptr)); - }; - } - - public: - template >> - ObjectResolver(const ObjectResolver& other) - : shared_object_ptr_(other.shared_object_ptr_), - accessor_(CreateAccessor(other.accessor_)) {} - - template >> - ObjectResolver(ObjectResolver&& other) - : shared_object_ptr_(std::move(other.shared_object_ptr_)), - accessor_(CreateAccessor(std::move(other.accessor_))) {} - - ObjectResolver(const ObjectResolver&) = default; - ObjectResolver& operator=(const ObjectResolver&) = default; - ObjectResolver(ObjectResolver&&) = default; - ObjectResolver& operator=(ObjectResolver&&) = default; - ~ObjectResolver() = default; - - template >> - ObjectResolver& operator=(const ObjectResolver& other) { - if (this != &other) { - this->shared_object_ptr_ = other.shared_object_ptr_; - this->accessor_ = CreateAccessor(other.accessor_); - } - return *this; - } - - template >> - ObjectResolver& operator=(ObjectResolver&& other) { - if (this != &other) { - this->shared_object_ptr_ = std::move(other.shared_object_ptr_); - this->accessor_ = CreateAccessor(std::move(other.shared_object_ptr_)); - } - return *this; - } - - bool IsValid() const { return this->shared_object_ptr_ != nullptr; } - - T* Resolve() const { - assert(IsValid()); - return this->accessor_(this->shared_object_ptr_); - } - - /** - * @remarks So this class can be used as a functor. - */ - T* operator()() const { return Resolve(); } - - template >> - operator ObjectResolver() const { - return ObjectResolver(*this); - } - - private: - void SetResolvedObject(T* o) { - assert(IsValid()); - *this->shared_object_ptr_ = o; - } - - private: - std::shared_ptr shared_object_ptr_; - std::function&)> accessor_; -}; - -/** - * @remarks - * This class is not copyable and movable since subclass is polymorphic and - * copying is then nonsense. However, you can even delete move capability in - * subclass because it may also be nonsense for subclass. The move capability is - * optional. - * - * Whether this class needs to be thread-safe still has to be considered. - */ -template -class SelfResolvable { - public: - SelfResolvable() : resolver_(CastToSubClass()) {} - SelfResolvable(const SelfResolvable&) = delete; - SelfResolvable& operator=(const SelfResolvable&) = delete; - - // Resolvers to old object will resolve to new object. - SelfResolvable(SelfResolvable&& other) - : resolver_(std::move(other.resolver_)) { - this->resolver_.SetResolvedObject(CastToSubClass()); - } - - // Old resolvers for this object will resolve to nullptr. - // Other's resolvers will now resolve to this. - SelfResolvable& operator=(SelfResolvable&& other) { - if (this != &other) { - this->resolver_ = std::move(other.resolver_); - this->resolver_.SetResolvedObject(CastToSubClass()); - } - return *this; - } - - virtual ~SelfResolvable() { - if (this->resolver_.IsValid()) { - this->resolver_.SetResolvedObject(nullptr); - } - } - - ObjectResolver CreateResolver() { return resolver_; } - - private: - T* CastToSubClass() { return static_cast(this); } - - private: - ObjectResolver resolver_; -}; -} // namespace cru diff --git a/include/cru/common/String.h b/include/cru/common/String.h deleted file mode 100644 index 21a3db51..00000000 --- a/include/cru/common/String.h +++ /dev/null @@ -1,492 +0,0 @@ -#pragma once -#include "Base.h" - -#include "Buffer.h" -#include "Range.h" -#include "StringToNumberConverter.h" -#include "StringUtil.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace cru { -class StringView; - -class CRU_BASE_API String { - public: - using value_type = char16_t; - using size_type = Index; - using difference_type = Index; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using iterator = value_type*; - using const_iterator = const value_type*; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - - public: - static String FromUtf8(const char* str); - static String FromUtf8(const char* str, Index size); - static String FromUtf8(const std::byte* str, Index size); - static String FromUtf8(std::string_view str) { - return FromUtf8(str.data(), str.size()); - } - static String FromUtf8(const Buffer& buffer); - - static String FromUtf16(const char16_t* str) { return String(str); } - static String FromUtf16(const char16_t* str, Index size) { - return String(str, size); - } - static String FromUtf16(std::u16string_view str) { - return FromUtf16(str.data(), str.size()); - } - - static inline String From(StringView str); - - // Never use this if you don't know what this mean! - static String FromBuffer(pointer buffer, Index size, Index capacity) { - return String{from_buffer_tag{}, buffer, size, capacity}; - } - - static String FromStdPath(const std::filesystem::path& path); - -#ifdef CRU_PLATFORM_WINDOWS - static String FromUtf16(wchar_t* str) { return String(str); } - static String FromUtf16(wchar_t* str, Index size) { - return String(str, size); - } -#endif - - public: - String() = default; - - String(const_pointer str); - String(const_pointer str, size_type size); - - template - String(const char16_t (&str)[size]) - : String(reinterpret_cast(str), size - 1) {} - - template - String(Iter start, Iter end) { - for (; start != end; start++) { - append(*start); - } - } - - String(size_type size, value_type ch = 0); - - String(std::initializer_list l); - - explicit String(StringView str); - -#ifdef CRU_PLATFORM_WINDOWS - String(const wchar_t* str); - String(const wchar_t* str, Index size); - String(const std::wstring& str) : String(str.data(), str.size()) {} -#endif - - String(const String& other); - String(String&& other) noexcept; - - String& operator=(const String& other); - String& operator=(String&& other) noexcept; - - ~String(); - - private: - struct from_buffer_tag {}; - String(from_buffer_tag, pointer buffer, Index size, Index capacity); - - public: - bool empty() const { return this->size_ == 0; } - Index size() const { return this->size_; } - Index length() const { return this->size(); } - Index capacity() const { return this->capacity_; } - pointer data() { return this->buffer_; } - const_pointer data() const { return this->buffer_; } - - void resize(Index new_size); - void reserve(Index new_capacity); - void shrink_to_fit(); - - reference front() { return this->operator[](0); } - const_reference front() const { return this->operator[](0); } - - reference back() { return this->operator[](size_ - 1); } - const_reference back() const { return this->operator[](size_ - 1); } - - const_pointer c_str() const { return buffer_; } - - reference operator[](Index index) { return buffer_[index]; } - const_reference operator[](Index index) const { return buffer_[index]; } - - public: - iterator begin() { return this->buffer_; } - const_iterator begin() const { return this->buffer_; } - const_iterator cbegin() const { return this->buffer_; } - - iterator end() { return this->buffer_ + this->size_; } - const_iterator end() const { return this->buffer_ + this->size_; } - const_iterator cend() const { return this->buffer_ + this->size_; } - - reverse_iterator rbegin() { return reverse_iterator{end()}; } - const_reverse_iterator rbegin() const { - return const_reverse_iterator{end()}; - } - const_reverse_iterator crbegin() const { - return const_reverse_iterator{cend()}; - } - - reverse_iterator rend() { return reverse_iterator{begin()}; } - const_reverse_iterator rend() const { - return const_reverse_iterator{begin()}; - } - const_reverse_iterator crend() const { - return const_reverse_iterator{cbegin()}; - } - - public: - void clear(); - iterator insert(const_iterator pos, value_type value) { - return this->insert(pos, &value, 1); - } - iterator insert(const_iterator pos, const_iterator str, Index size); - iterator insert(const_iterator pos, StringView str); - iterator erase(const_iterator pos) { return this->erase(pos, pos + 1); } - iterator erase(const_iterator start, const_iterator end); - void push_back(value_type value) { this->append(value); } - void pop_back() { this->erase(cend() - 1); } - void append(value_type value) { this->insert(cend(), value); } - void append(const_iterator str, Index size) { - this->insert(cend(), str, size); - } - inline void append(StringView str); - - String substr(size_type start, size_type size = -1) const { - if (size == -1) { - size = this->size_ - start; - } - return String(this->buffer_ + start, size); - } - - String& operator+=(value_type value) { - this->append(value); - return *this; - } - String& operator+=(StringView other); - - public: - operator std::u16string_view() const { - return std::u16string_view(data(), size()); - } - - StringView View() const; - - public: - Index Find(value_type value, Index start = 0) const; - std::vector Split(value_type separator, - bool remove_space_line = false) const; - std::vector SplitToLines(bool remove_space_line = false) const; - - bool StartWith(StringView str) const; - bool EndWith(StringView str) const; - - String& TrimStart(); - String& TrimEnd(); - String& Trim(); - - public: - void AppendCodePoint(CodePoint code_point); - - Utf16CodePointIterator CodePointIterator() const { - return Utf16CodePointIterator(buffer_, size_); - } - - Index IndexFromCodeUnitToCodePoint(Index code_unit_index) const; - Index IndexFromCodePointToCodeUnit(Index code_point_index) const; - Range RangeFromCodeUnitToCodePoint(Range code_unit_range) const; - Range RangeFromCodePointToCodeUnit(Range code_point_range) const; - - template - std::enable_if_t, TInteger> ParseToInteger( - Index* processed_characters_count, unsigned flags, int base) const; - - int ParseToInt(Index* processed_characters_count = nullptr, - StringToNumberFlag flags = {}, int base = 0) const; - long long ParseToLongLong(Index* processed_characters_count = nullptr, - StringToNumberFlag flags = {}, int base = 0) const; - - float ParseToFloat(Index* processed_characters_count = nullptr, - StringToNumberFlag flags = {}) const; - double ParseToDouble(Index* processed_characters_count = nullptr, - StringToNumberFlag flags = {}) const; - std::vector ParseToFloatList(value_type separator = u' ') const; - std::vector ParseToDoubleList(value_type separator = u' ') const; - -#ifdef CRU_PLATFORM_WINDOWS - const wchar_t* WinCStr() const { - return reinterpret_cast(c_str()); - } -#endif - - template - String Format(T&&... args) const; - - std::string ToUtf8() const; - Buffer ToUtf8Buffer(bool end_zero = true) const; - - int Compare(const String& other) const; - int CaseInsensitiveCompare(const String& other) const; - bool CaseInsensitiveEqual(const String& other) const { - return CaseInsensitiveCompare(other) == 0; - } - - private: - static char16_t kEmptyBuffer[1]; - - private: - char16_t* buffer_ = kEmptyBuffer; - Index size_ = 0; // not including trailing '\0' - Index capacity_ = 0; // always 1 smaller than real buffer size -}; - -std::ostream& CRU_BASE_API operator<<(std::ostream& os, const String& value); - -class CRU_BASE_API StringView { - public: - using value_type = char16_t; - using size_type = Index; - using difference_type = Index; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using iterator = const value_type*; - using const_iterator = const value_type*; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - - StringView() = default; - - constexpr StringView(const_pointer ptr, Index size) - : ptr_(ptr), size_(size) {} - - template - constexpr StringView(const value_type (&array)[size]) - : StringView(array, size - 1) {} - - StringView(const String& str) : StringView(str.data(), str.size()) {} - - CRU_DEFAULT_COPY(StringView) - CRU_DEFAULT_MOVE(StringView) - - ~StringView() = default; - - bool empty() const { return size_ == 0; } - Index size() const { return size_; } - const value_type* data() const { return ptr_; } - - public: - iterator begin() { return this->ptr_; } - const_iterator begin() const { return this->ptr_; } - const_iterator cbegin() const { return this->ptr_; } - - iterator end() { return this->ptr_ + this->size_; } - const_iterator end() const { return this->ptr_ + this->size_; } - const_iterator cend() const { return this->ptr_ + this->size_; } - - reverse_iterator rbegin() { return reverse_iterator{end()}; } - const_reverse_iterator rbegin() const { - return const_reverse_iterator{end()}; - } - const_reverse_iterator crbegin() const { - return const_reverse_iterator{cend()}; - } - - reverse_iterator rend() { return reverse_iterator{begin()}; } - const_reverse_iterator rend() const { - return const_reverse_iterator{begin()}; - } - const_reverse_iterator crend() const { - return const_reverse_iterator{cbegin()}; - } - - StringView substr(Index pos); - StringView substr(Index pos, Index size); - - value_type operator[](Index index) const { return ptr_[index]; } - - operator std::u16string_view() const { - return std::u16string_view(data(), size()); - } - - public: - int Compare(const StringView& other) const; - int CaseInsensitiveCompare(const StringView& other) const; - bool CaseInsensitiveEqual(const StringView& other) const { - return CaseInsensitiveCompare(other) == 0; - } - - String ToString() const { return String(ptr_, size_); } - - Utf16CodePointIterator CodePointIterator() const { - return Utf16CodePointIterator(ptr_, size_); - } - - Index Find(value_type value, Index start = 0) const; - std::vector Split(value_type separator, - bool remove_space_line = false) const; - std::vector SplitToLines(bool remove_space_line = false) const; - - bool StartWith(StringView str) const; - bool EndWith(StringView str) const; - - Index IndexFromCodeUnitToCodePoint(Index code_unit_index) const; - Index IndexFromCodePointToCodeUnit(Index code_point_index) const; - Range RangeFromCodeUnitToCodePoint(Range code_unit_range) const; - Range RangeFromCodePointToCodeUnit(Range code_point_range) const; - - template - std::enable_if_t, TInteger> ParseToInteger( - Index* processed_characters_count, StringToNumberFlag flags, - int base) const { - auto utf8_string = ToUtf8(); - auto result = StringToIntegerConverter(flags, base) - .Parse(utf8_string.data(), utf8_string.size(), - processed_characters_count); - return result.negate ? -result.value : result.value; - } - - int ParseToInt(Index* processed_characters_count = nullptr, - StringToNumberFlag flags = {}, int base = 0) const; - long long ParseToLongLong(Index* processed_characters_count = nullptr, - StringToNumberFlag flags = {}, int base = 0) const; - - float ParseToFloat(Index* processed_characters_count = nullptr, - StringToNumberFlag flags = {}) const; - double ParseToDouble(Index* processed_characters_count = nullptr, - StringToNumberFlag flags = {}) const; - std::vector ParseToFloatList(value_type separator = u' ') const; - std::vector ParseToDoubleList(value_type separator = u' ') const; - - std::string ToUtf8() const; - Buffer ToUtf8Buffer(bool end_zero = true) const; - - private: - const char16_t* ptr_; - Index size_; -}; - -CRU_DEFINE_COMPARE_OPERATORS(String) - -inline String operator+(const String& left, const String& right) { - String result; - result += left; - result += right; - return result; -} - -inline String operator+(String::value_type left, const String& right) { - String result; - result += left; - result += right; - return result; -} - -inline String operator+(const String& left, String::value_type right) { - String result; - result += left; - result += right; - return result; -} - -CRU_DEFINE_COMPARE_OPERATORS(StringView) - -inline String::iterator String::insert(const_iterator pos, StringView str) { - return insert(pos, str.data(), str.size()); -} - -inline void String::append(StringView str) { - this->append(str.data(), str.size()); -} - -inline String String::From(StringView str) { return str.ToString(); } - -inline String::String(StringView str) : String(str.data(), str.size()) {} - -inline String ToString(StringView value) { return value.ToString(); } - -inline CodePoint Utf16PreviousCodePoint(StringView str, Index current, - Index* previous_position) { - return Utf16PreviousCodePoint(str.data(), str.size(), current, - previous_position); -} - -inline CodePoint Utf16NextCodePoint(StringView str, Index current, - Index* next_position) { - return Utf16NextCodePoint(str.data(), str.size(), current, next_position); -} - -inline bool Utf16IsValidInsertPosition(StringView str, Index position) { - return Utf16IsValidInsertPosition(str.data(), str.size(), position); -} - -// Return position after the character making predicate returns true or 0 if no -// character doing so. -inline Index CRU_BASE_API -Utf16BackwardUntil(StringView str, Index position, - const std::function& predicate) { - return Utf16BackwardUntil(str.data(), str.size(), position, predicate); -} -// Return position before the character making predicate returns true or -// str.size() if no character doing so. -inline Index CRU_BASE_API -Utf16ForwardUntil(StringView str, Index position, - const std::function& predicate) { - return Utf16ForwardUntil(str.data(), str.size(), position, predicate); -} - -inline Index Utf16PreviousWord(StringView str, Index position, - bool* is_space = nullptr) { - return Utf16PreviousWord(str.data(), str.size(), position, is_space); -} - -inline Index Utf16NextWord(StringView str, Index position, - bool* is_space = nullptr) { - return Utf16NextWord(str.data(), str.size(), position, is_space); -} - -String CRU_BASE_API ToLower(StringView s); -String CRU_BASE_API ToUpper(StringView s); - -template -std::enable_if_t, TInteger> String::ParseToInteger( - Index* processed_characters_count, unsigned flags, int base) const { - View().ParseToInteger(processed_characters_count, flags, base); -} - -} // namespace cru - -template <> -struct std::hash { - std::size_t operator()(const cru::String& value) const { - return std::hash{}(std::u16string_view( - reinterpret_cast(value.data()), value.size())); - } -}; - -template <> -struct std::hash { - std::size_t operator()(const cru::StringView& value) const { - return std::hash{}(std::u16string_view( - reinterpret_cast(value.data()), value.size())); - } -}; diff --git a/include/cru/common/StringToNumberConverter.h b/include/cru/common/StringToNumberConverter.h deleted file mode 100644 index 758b26c8..00000000 --- a/include/cru/common/StringToNumberConverter.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once -#include "Base.h" -#include "Bitmask.h" - -#include -#include - -namespace cru { -namespace details { -struct StringToNumberFlagTag {}; -} // namespace details - -using StringToNumberFlag = Bitmask; - -struct StringToNumberFlags { - constexpr static StringToNumberFlag kAllowLeadingSpaces = - StringToNumberFlag::FromOffset(0); - constexpr static StringToNumberFlag kAllowTrailingSpaces = - StringToNumberFlag::FromOffset(1); - constexpr static StringToNumberFlag kAllowTrailingJunk = - StringToNumberFlag::FromOffset(2); - constexpr static StringToNumberFlag kAllowLeadingZeroForInteger = - StringToNumberFlag::FromOffset(3); - constexpr static StringToNumberFlag kThrowOnError = - StringToNumberFlag::FromOffset(4); -}; - -template -struct IStringToNumberConverter : virtual Interface { - virtual TResult Parse(const char* str, Index size, - Index* processed_characters_count) const = 0; - - template - TResult Parse(const char (&str)[Size], - Index* processed_characters_count) const { - return Parse(str, Size - 1, processed_characters_count); - } -}; - -struct CRU_BASE_API StringToIntegerResult { - StringToIntegerResult() = default; - StringToIntegerResult(bool negate, unsigned long long value) - : negate(negate), value(value) {} - - bool negate; - unsigned long long value; -}; - -inline bool CRU_BASE_API operator==(const StringToIntegerResult& left, - const StringToIntegerResult& right) { - return left.negate == right.negate && left.value == right.value; -} - -inline bool CRU_BASE_API operator!=(const StringToIntegerResult& left, - const StringToIntegerResult& right) { - return !(left == right); -} - -inline std::ostream& CRU_BASE_API -operator<<(std::ostream& stream, const StringToIntegerResult& result) { - return stream << "StringToIntegerConverterImplResult(" - << (result.negate ? "-" : "") << result.value << ")"; -} - -/** - * \brief A converter that convert number into long long. - */ -struct CRU_BASE_API StringToIntegerConverter - : IStringToNumberConverter { - public: - explicit StringToIntegerConverter(StringToNumberFlag flags, int base = 0) - : flags(flags), base(base) {} - - bool CheckParams() const; - - /** - * \brief Convert string to long long. - * \param str The string to convert. - * \param size The size of the string. - * \param processed_characters_count The number of characters that were - * processed. Or nullptr to not retrieve. - */ - StringToIntegerResult Parse(const char* str, Index size, - Index* processed_characters_count) const override; - using IStringToNumberConverter::Parse; - - StringToNumberFlag flags; - /** - * \brief The base of the number used for parse or 0 for auto detect. - * \remarks Base can only be of range [2, 36] or 0. If base is 0, decimal is - * assumed by default ,or if str is started with "0x" or "0X" hexadecimal is - * assumed, or if str is started with a single "0" octoral is assumed, or if - * str is started with "0b" or "0B" binary is assumed. Otherwise it is an - * error. - */ - int base; -}; - -struct CRU_BASE_API StringToFloatConverter { - StringToFloatConverter(StringToNumberFlag flags) : flags(flags) {} - - double Parse(const char* str, Index size, - Index* processed_characters_count) const; - - StringToNumberFlag flags; -}; -} // namespace cru diff --git a/include/cru/common/StringUtil.h b/include/cru/common/StringUtil.h deleted file mode 100644 index 8f085283..00000000 --- a/include/cru/common/StringUtil.h +++ /dev/null @@ -1,226 +0,0 @@ -#pragma once -#include "Base.h" - -#include -#include - -namespace cru { -using CodePoint = std::int32_t; -constexpr CodePoint k_invalid_code_point = -1; - -inline bool IsUtf16SurrogatePairCodeUnit(char16_t c) { - return c >= 0xD800 && c <= 0xDFFF; -} - -inline bool IsUtf16SurrogatePairLeading(char16_t c) { - return c >= 0xD800 && c <= 0xDBFF; -} - -inline bool IsUtf16SurrogatePairTrailing(char16_t c) { - return c >= 0xDC00 && c <= 0xDFFF; -} - -CodePoint CRU_BASE_API Utf8NextCodePoint(const char* ptr, Index size, - Index current, Index* next_position); - -CodePoint CRU_BASE_API Utf16NextCodePoint(const char16_t* ptr, Index size, - Index current, Index* next_position); -CodePoint CRU_BASE_API Utf16PreviousCodePoint(const char16_t* ptr, Index size, - Index current, - Index* previous_position); - -template -using NextCodePointFunctionType = CodePoint (*)(const CharType*, Index, Index, - Index*); - -template NextCodePointFunction> -class CodePointIterator { - public: - using difference_type = Index; - using value_type = CodePoint; - using pointer = void; - using reference = value_type; - using iterator_category = std::forward_iterator_tag; - - public: - struct past_end_tag_t {}; - - explicit CodePointIterator(const CharType* ptr, Index size, Index current = 0) - : ptr_(ptr), size_(size), position_(current) {} - explicit CodePointIterator(const CharType* ptr, Index size, past_end_tag_t) - : ptr_(ptr), size_(size), position_(size) {} - - CRU_DEFAULT_COPY(CodePointIterator) - CRU_DEFAULT_MOVE(CodePointIterator) - - ~CodePointIterator() = default; - - public: - const CharType* GetPtr() const { return ptr_; } - Index GetSize() const { return size_; } - Index GetPosition() const { return position_; } - - bool IsPastEnd() const { return position_ == static_cast(size_); } - - public: - CodePointIterator begin() const { return *this; } - CodePointIterator end() const { - return CodePointIterator{ptr_, size_, past_end_tag_t{}}; - } - - public: - bool operator==(const CodePointIterator& other) const { - // You should compare iterator that iterate on the same string. - Expects(this->ptr_ == other.ptr_ && this->size_ == other.size_); - return this->position_ == other.position_; - } - bool operator!=(const CodePointIterator& other) const { - return !this->operator==(other); - } - - CodePointIterator& operator++() { - Expects(!IsPastEnd()); - Forward(); - return *this; - } - - CodePointIterator operator++(int) { - Expects(!IsPastEnd()); - CodePointIterator old = *this; - Forward(); - return old; - } - - CodePoint operator*() const { - return NextCodePointFunction(ptr_, size_, position_, &next_position_cache_); - } - - private: - void Forward() { - if (next_position_cache_ > position_) { - position_ = next_position_cache_; - } else { - NextCodePointFunction(ptr_, size_, position_, &position_); - } - } - - private: - const CharType* ptr_; - Index size_; - Index position_; - mutable Index next_position_cache_ = 0; -}; - -using Utf8CodePointIterator = CodePointIterator; - -using Utf16CodePointIterator = CodePointIterator; - -namespace details { -template -inline std::enable_if_t, ReturnType> ExtractBits( - UInt n) { - return static_cast(n & ((1u << number_of_bit) - 1)); -} -} // namespace details - -template -std::enable_if_t, bool> -Utf8EncodeCodePointAppend(CodePoint code_point, CharWriter&& writer) { - auto write_continue_byte = [&writer](std::uint8_t byte6) { - writer((1u << 7) + (((1u << 6) - 1) & byte6)); - }; - - if (code_point >= 0 && code_point <= 0x007F) { - writer(static_cast(code_point)); - return true; - } else if (code_point >= 0x0080 && code_point <= 0x07FF) { - std::uint32_t unsigned_code_point = code_point; - writer( - static_cast(details::ExtractBits( - (unsigned_code_point >> 6)) + - 0b11000000)); - write_continue_byte(details::ExtractBits( - unsigned_code_point)); - return true; - } else if (code_point >= 0x0800 && code_point <= 0xFFFF) { - std::uint32_t unsigned_code_point = code_point; - writer( - static_cast(details::ExtractBits( - (unsigned_code_point >> (6 * 2))) + - 0b11100000)); - write_continue_byte(details::ExtractBits( - unsigned_code_point >> 6)); - write_continue_byte(details::ExtractBits( - unsigned_code_point)); - return true; - } else if (code_point >= 0x10000 && code_point <= 0x10FFFF) { - std::uint32_t unsigned_code_point = code_point; - writer( - static_cast(details::ExtractBits( - (unsigned_code_point >> (6 * 3))) + - 0b11110000)); - write_continue_byte(details::ExtractBits( - unsigned_code_point >> (6 * 2))); - write_continue_byte(details::ExtractBits( - unsigned_code_point >> 6)); - write_continue_byte(details::ExtractBits( - unsigned_code_point)); - return true; - } else { - return false; - } -} - -template -std::enable_if_t, bool> -Utf16EncodeCodePointAppend(CodePoint code_point, CharWriter&& writer) { - if ((code_point >= 0 && code_point <= 0xD7FF) || - (code_point >= 0xE000 && code_point <= 0xFFFF)) { - writer(static_cast(code_point)); - return true; - } else if (code_point >= 0x10000 && code_point <= 0x10FFFF) { - std::uint32_t u = code_point - 0x10000; - writer(static_cast( - details::ExtractBits(u >> 10) + - 0xD800u)); - writer(static_cast( - details::ExtractBits(u) + 0xDC00u)); - return true; - } else { - return false; - } -} - -// If given s is not a valid utf16 string, return value is UD. -bool CRU_BASE_API Utf16IsValidInsertPosition(const char16_t* ptr, Index size, - Index position); - -// Return position after the character making predicate returns true or 0 if no -// character doing so. -Index CRU_BASE_API -Utf16BackwardUntil(const char16_t* ptr, Index size, Index position, - const std::function& predicate); -// Return position before the character making predicate returns true or -// str.size() if no character doing so. -Index CRU_BASE_API -Utf16ForwardUntil(const char16_t* ptr, Index size, Index position, - const std::function& predicate); - -Index CRU_BASE_API Utf16PreviousWord(const char16_t* ptr, Index size, - Index position, bool* is_space = nullptr); -Index CRU_BASE_API Utf16NextWord(const char16_t* ptr, Index size, - Index position, bool* is_space = nullptr); - -char16_t CRU_BASE_API ToLower(char16_t c); -char16_t CRU_BASE_API ToUpper(char16_t c); - -bool CRU_BASE_API IsWhitespace(char16_t c); -bool CRU_BASE_API IsDigit(char16_t c); - -Utf8CodePointIterator CRU_BASE_API CreateUtf8Iterator(const std::byte* buffer, - Index size); -Utf8CodePointIterator CRU_BASE_API -CreateUtf8Iterator(const std::vector& buffer); - -} // namespace cru diff --git a/include/cru/common/SubProcess.h b/include/cru/common/SubProcess.h deleted file mode 100644 index fbe8ad2b..00000000 --- a/include/cru/common/SubProcess.h +++ /dev/null @@ -1,258 +0,0 @@ -#pragma once -#include "Base.h" -#include "Exception.h" -#include "String.h" -#include "io/Stream.h" - -#include -#include -#include -#include -#include -#include - -namespace cru { -enum class SubProcessStatus { - /** - * @brief The process has not been created and started. - */ - Prepare, - /** - * @brief The process is failed to start. - */ - FailedToStart, - /** - * @brief The process is running now. - */ - Running, - /** - * @brief The process has been exited. - */ - Exited, -}; - -class CRU_BASE_API SubProcessException : public Exception { - public: - using Exception::Exception; -}; - -class CRU_BASE_API SubProcessFailedToStartException - : public SubProcessException { - public: - using SubProcessException::SubProcessException; -}; - -class CRU_BASE_API SubProcessInternalException : public SubProcessException { - public: - using SubProcessException::SubProcessException; -}; - -struct SubProcessStartInfo { - String program; - std::vector arguments; - std::unordered_map environments; -}; - -enum class SubProcessExitType { - Unknown, - Normal, - Signal, -}; - -struct SubProcessExitResult { - SubProcessExitType exit_type; - int exit_code; - int exit_signal; - bool has_core_dump; - - bool IsSuccess() const { - return exit_type == SubProcessExitType::Normal && exit_code == 0; - } - - static SubProcessExitResult Unknown() { - return {SubProcessExitType::Unknown, 0, 0, false}; - } - - static SubProcessExitResult Normal(int exit_code) { - return {SubProcessExitType::Normal, exit_code, 0, false}; - } - - static SubProcessExitResult Signal(int exit_signal, bool has_core_dump) { - return {SubProcessExitType::Normal, 0, exit_signal, has_core_dump}; - } -}; - -struct IPlatformSubProcessImpl : virtual Interface { - /** - * @brief Create and start a real process. - * - * If the program can't be created or start, an exception should be - * thrown. - * - * Implementation should fill internal data of the new process and start - * it. - * - * This method will be called only once in first call of `Start` on this - * thread with lock holdDefaultConstructible. - */ - virtual void PlatformCreateProcess(const SubProcessStartInfo& start_info) = 0; - - /** - * @brief Wait for the created process forever and return the exit result - * when process stops. - * - * Implementation should wait for the real process forever, after that, - * fill internal data and returns exit result. - * - * This method will be called only once on another thread after - * `PlatformCreateProcess` returns successfully - */ - virtual SubProcessExitResult PlatformWaitForProcess() = 0; - - /** - * @brief Kill the process immediately. - * - * This method will be called only once on this thread given - * `PlatformCreateProcess` returns successfully. There will be a window - * that the window already exits but the status has not been updated and - * this is called. So handle this gracefully and write to internal data - * carefully. - */ - virtual void PlatformKillProcess() = 0; - - virtual io::Stream* GetStdinStream() = 0; - virtual io::Stream* GetStdoutStream() = 0; - virtual io::Stream* GetStderrStream() = 0; -}; - -/** - * @brief A wrapper platform process. It is one-time, which means it - * starts and exits and can't start again. - * - * TODO: Current implementation has a problem. If the process does not exit for - * a long time, the resource related to it will not be released. It may cause a - * leak. - */ -class PlatformSubProcess : public Object { - CRU_DEFINE_CLASS_LOG_TAG(u"PlatformSubProcess") - - private: - struct State { - explicit State(SubProcessStartInfo start_info, - std::shared_ptr impl) - : start_info(std::move(start_info)), impl(std::move(impl)) {} - - std::mutex mutex; - std::condition_variable condition_variable; - SubProcessStartInfo start_info; - SubProcessExitResult exit_result; - SubProcessStatus status = SubProcessStatus::Prepare; - bool killed = false; - std::shared_ptr impl; - }; - - public: - PlatformSubProcess(SubProcessStartInfo start_info, - std::shared_ptr impl); - - ~PlatformSubProcess() override; - - /** - * @brief Create and start a real process. If the process can't be created or - * start, `SubProcessFailedToStartException` will be thrown. If this function - * is already called once, `SubProcessException` will be thrown. Ensure only - * call this method once. - */ - void Start(); - - /** - * @brief Wait for the process to exit optionally for at most `wait_time`. If - * the process already exits, it will return immediately. If the process has - * not started or failed to start, `SubProcessException` will be thrown. - * Ensure `Start` is called and does not throw before calling this. - * - * @remarks You may wish this returns bool to indicate whether it is timeout - * or the process exits. But no, even if it is timeout, the process may also - * have exited due to task schedule. - */ - void Wait(std::optional wait_time); - - /** - * @brief kill the process if it is running. If the process already exits, - * nothing will happen. If the process has not started or failed to start, - * `SubProcessException` will be throw. Ensure `Start` is called and does not - * throw before calling this. - */ - void Kill(); - - /** - * @brief Get the status of the process. - * 1. If the process has tried to start, aka `Start` is called, then this - * method will return one of `Running`, `FailedToStart`, `Exited`. - * 2. If it returns `Prepare`, `Start` is not called. - * 3. It does NOT guarantee that this return `Running` and the process is - * actually running. Because there might be a window that the process exits - * already but status is not updated. - */ - SubProcessStatus GetStatus(); - - /** - * @brief Get the exit result. If the process is not started, failed to start - * or running, `SubProcessException` will be thrown. - */ - SubProcessExitResult GetExitResult(); - - io::Stream* GetStdinStream(); - io::Stream* GetStdoutStream(); - io::Stream* GetStderrStream(); - - private: - std::shared_ptr state_; - std::unique_lock lock_; -}; - -class CRU_BASE_API SubProcess : public Object { - CRU_DEFINE_CLASS_LOG_TAG(u"SubProcess") - - public: - static SubProcess Create( - String program, std::vector arguments = {}, - std::unordered_map environments = {}); - - static SubProcessExitResult Call( - String program, std::vector arguments = {}, - std::unordered_map environments = {}); - - public: - SubProcess(SubProcessStartInfo start_info); - - CRU_DELETE_COPY(SubProcess) - - SubProcess(SubProcess&& other) = default; - SubProcess& operator=(SubProcess&& other) = default; - - ~SubProcess() override; - - public: - void Wait(std::optional wait_time = std::nullopt); - void Kill(); - - SubProcessStatus GetStatus(); - SubProcessExitResult GetExitResult(); - - io::Stream* GetStdinStream(); - io::Stream* GetStdoutStream(); - io::Stream* GetStderrStream(); - - void Detach(); - - bool IsValid() const { return platform_process_ != nullptr; } - explicit operator bool() const { return IsValid(); } - - private: - void CheckValid() const; - - private: - std::unique_ptr platform_process_; -}; -} // namespace cru diff --git a/include/cru/common/concurrent/ConcurrentQueue.h b/include/cru/common/concurrent/ConcurrentQueue.h deleted file mode 100644 index e311d5f9..00000000 --- a/include/cru/common/concurrent/ConcurrentQueue.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace cru::concurrent { -namespace details { -template -struct ConcurrentQueueNode { - ConcurrentQueueNode(T&& value, ConcurrentQueueNode* next = nullptr) - : value(std::move(value)), next(next) {} - - T value; - ConcurrentQueueNode* next; -}; -} // namespace details - -template -class ConcurrentQueue { - public: - ConcurrentQueue() {} - - ConcurrentQueue(const ConcurrentQueue&) = delete; - ConcurrentQueue& operator=(const ConcurrentQueue&) = delete; - - ~ConcurrentQueue() { - if (head_) { - auto node = head_; - while (node) { - auto next = node->next; - delete node; - node = next; - } - } - } - - public: - void Push(T&& value) { - std::unique_lock lock(mutex_); - if (head_ == nullptr) { - head_ = tail_ = new details::ConcurrentQueueNode(std::move(value)); - condition_variable_.notify_one(); - } else { - tail_->next = new details::ConcurrentQueueNode(std::move(value)); - tail_ = tail_->next; - } - } - - T Pull() { - std::unique_lock lock(mutex_); - if (head_ == nullptr) { - condition_variable_.wait(lock); - } - assert(head_ != nullptr); - auto value = std::move(head_->value); - auto next = head_->next; - delete head_; - head_ = next; - if (next == nullptr) { - tail_ = nullptr; - } - return value; - } - - std::optional Poll() { - std::unique_lock lock(mutex_); - if (head_ == nullptr) { - return std::nullopt; - } - auto value = std::move(head_->value); - auto next = head_->next; - delete head_; - head_ = next; - if (next == nullptr) { - tail_ = nullptr; - } - return value; - } - - private: - details::ConcurrentQueueNode* head_ = nullptr; - details::ConcurrentQueueNode* tail_ = nullptr; - - std::mutex mutex_; - std::condition_variable condition_variable_; -}; -} // namespace cru::concurrent diff --git a/include/cru/common/io/AutoReadStream.h b/include/cru/common/io/AutoReadStream.h deleted file mode 100644 index 759d5026..00000000 --- a/include/cru/common/io/AutoReadStream.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "BufferStream.h" -#include "Stream.h" - -#include -#include - -namespace cru::io { -struct AutoReadStreamOptions { - /** - * @brief Will be passed to BufferStreamOptions::block_size. - */ - Index block_size = 0; - - /** - * @brief Will be passed to BufferStreamOptions::total_size_limit. - */ - Index total_size_limit = 0; - - BufferStreamOptions GetBufferStreamOptions() const { - BufferStreamOptions options; - options.block_size = block_size; - options.total_size_limit = total_size_limit; - return options; - } -}; - -/** - * @brief A stream that wraps another stream and auto read it into a buffer in a - * background thread. - */ -class CRU_BASE_API AutoReadStream : public Stream { - public: - /** - * @brief Wrap a stream and auto read it in background. - * @param stream The stream to auto read. - * @param auto_delete Whether to delete the stream object in destructor. - * @param options Options to modify the behavior. - */ - AutoReadStream( - Stream* stream, bool auto_delete, - const AutoReadStreamOptions& options = AutoReadStreamOptions()); - - ~AutoReadStream() override; - - public: - CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE - - void BeginToDrop(bool auto_delete = true); - - protected: - Index DoRead(std::byte* buffer, Index offset, Index size) override; - Index DoWrite(const std::byte* buffer, Index offset, Index size) override; - void DoFlush() override; - - private: - void DoClose(); - - void BackgroundThreadRun(); - - private: - Stream* stream_; - bool auto_delete_; - - Index size_per_read_; - std::unique_ptr buffer_stream_; - std::mutex buffer_stream_mutex_; - - std::thread background_thread_; -}; -} // namespace cru::io diff --git a/include/cru/common/io/BufferStream.h b/include/cru/common/io/BufferStream.h deleted file mode 100644 index 5ebff546..00000000 --- a/include/cru/common/io/BufferStream.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include "../Buffer.h" -#include "../Exception.h" -#include "Stream.h" - -#include -#include -#include - -namespace cru::io { -class WriteAfterEofException : public Exception { - public: - using Exception::Exception; - ~WriteAfterEofException() override = default; -}; - -struct BufferStreamOptions { - /** - * Actually I have no ideas about the best value for this. May change it later - * when I get some ideas. - */ - constexpr static Index kDefaultBlockSize = 1024; - - /** - * @brief The size of a single buffer allocated each time new space is needed. - * Use default value if <= 0. - * - * When current buffer is full and there is no space for following data, a new - * buffer will be allocated and appended to the buffer list. Note if sum size - * of all buffers reaches the total_buffer_limit, no more buffer will be - * allocated but wait. - */ - Index block_size = 0; - - /** - * @brief Total size limit of saved data in buffer. No limit if <= 0. - * - * The size will be floor(total_size_limit / block_size). When the buffer is - * filled, it will block and wait for user to read to get free space of buffer - * to continue read. - */ - Index total_size_limit = 0; - - Index GetBlockSizeOrDefault() const { - return block_size <= 0 ? kDefaultBlockSize : block_size; - } - - Index GetMaxBlockCount() const { - return total_size_limit / GetBlockSizeOrDefault(); - } -}; - -/** - * @brief SPSC (Single Producer Single Consumer) buffer stream. - * - * If used by multiple producer or multiple consumer, the behavior is undefined. - */ -class BufferStream : public Stream { - public: - BufferStream(const BufferStreamOptions& options); - ~BufferStream() override; - - CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE - - void SetEof(); - - protected: - Index DoRead(std::byte* buffer, Index offset, Index size) override; - Index DoWrite(const std::byte* buffer, Index offset, Index size) override; - - private: - void DoClose(); - - private: - Index block_size_; - Index max_block_count_; - - std::list buffer_list_; - bool eof_; - - std::mutex mutex_; - std::condition_variable condition_variable_; -}; -} // namespace cru::io diff --git a/include/cru/common/io/CFileStream.h b/include/cru/common/io/CFileStream.h deleted file mode 100644 index 0b58bdc9..00000000 --- a/include/cru/common/io/CFileStream.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "Stream.h" - -#include - -namespace cru::io { -class CRU_BASE_API CFileStream : public Stream { - public: - CFileStream(const char* path, const char* mode); - explicit CFileStream(std::FILE* file, bool readable = true, - bool writable = true, bool auto_close = true); - - CRU_DELETE_COPY(CFileStream) - CRU_DELETE_MOVE(CFileStream) - - ~CFileStream() override; - - public: - CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE - - std::FILE* GetHandle() const; - - protected: - Index DoSeek(Index offset, SeekOrigin origin) override; - Index DoTell() override; - void DoRewind() override; - Index DoRead(std::byte* buffer, Index offset, Index size) override; - Index DoWrite(const std::byte* buffer, Index offset, Index size) override; - void DoFlush() override; - - private: - void DoClose(); - - private: - std::FILE* file_; - bool auto_close_; -}; -} // namespace cru::io diff --git a/include/cru/common/io/MemoryStream.h b/include/cru/common/io/MemoryStream.h deleted file mode 100644 index a1f90c3b..00000000 --- a/include/cru/common/io/MemoryStream.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "Stream.h" - -#include - -namespace cru::io { -class CRU_BASE_API MemoryStream : public Stream { - public: - MemoryStream( - std::byte* buffer, Index size, bool read_only = false, - std::function release_func = {}); - - ~MemoryStream() override; - - public: - void Close() override; - - std::byte* GetBuffer() const { return buffer_; } - - protected: - Index DoSeek(Index offset, SeekOrigin origin) override; - Index DoGetSize() override { return size_; } - Index DoRead(std::byte* buffer, Index offset, Index size) override; - Index DoWrite(const std::byte* buffer, Index offset, Index size) override; - - private: - void DoClose(); - - private: - std::byte* buffer_; - Index size_; - Index position_; - std::function release_func_; -}; -} // namespace cru::io diff --git a/include/cru/common/io/OpenFileFlag.h b/include/cru/common/io/OpenFileFlag.h deleted file mode 100644 index 4a5789fb..00000000 --- a/include/cru/common/io/OpenFileFlag.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "../Bitmask.h" - -namespace cru::io { -namespace details { -struct OpenFileFlagTag {}; -} // namespace details -using OpenFileFlag = Bitmask; - -struct OpenFileFlags { - /** - * \brief for reading - * If the file does not exist, FileNotExistException should be thrown. - */ - static constexpr OpenFileFlag Read{0x1}; - - /** - * \brief for writing - * If the file does not exist and Create is not specified, - * FileNotExistException should be thrown. - */ - static constexpr OpenFileFlag Write{0x2}; - - /** - * \brief when writing, seek to end first - * Only effective for writing. - */ - static constexpr OpenFileFlag Append{0x4}; - - /** - * \brief when writing, truncate the file to empty - * Only effective for writing. - * So the content is erased! Be careful! - */ - static constexpr OpenFileFlag Truncate{0x8}; - - /** - * \brief when writing, if the file does not exist, create one - * Only effective for writing. When file does not exist, FileNotExistException - * will NOT be thrown and a new file will be created. - */ - static constexpr OpenFileFlag Create{0x10}; - - /** - * TODO: ??? - */ - static constexpr OpenFileFlag Exclusive{0x20}; -}; - -/** - * Append, Truncate, Create must be used with Write. - * Append and Truncate must not be used together. - */ -bool CheckOpenFileFlag(OpenFileFlag flags); -} // namespace cru::io diff --git a/include/cru/common/io/ProxyStream.h b/include/cru/common/io/ProxyStream.h deleted file mode 100644 index 42ec9dfd..00000000 --- a/include/cru/common/io/ProxyStream.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "Stream.h" - -#include - -namespace cru::io { -struct ProxyStreamHandlers { - std::function seek; - std::function read; - std::function write; - std::function flush; - - /** - * @brief This method will be only called once when `Close` is called or the - * stream is destructed. - */ - std::function close; -}; - -class ProxyStream : public Stream { - public: - explicit ProxyStream(ProxyStreamHandlers handlers); - - ~ProxyStream() override; - - public: - CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE - - protected: - Index DoSeek(Index offset, SeekOrigin origin) override; - Index DoRead(std::byte* buffer, Index offset, Index size) override; - Index DoWrite(const std::byte* buffer, Index offset, Index size) override; - void DoFlush() override; - - private: - void DoClose(); - - private: - ProxyStreamHandlers handlers_; -}; -} // namespace cru::io diff --git a/include/cru/common/io/Resource.h b/include/cru/common/io/Resource.h deleted file mode 100644 index 1d5313a6..00000000 --- a/include/cru/common/io/Resource.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "../Base.h" - -#include - -namespace cru::io { -std::filesystem::path CRU_BASE_API GetResourceDir(); -} diff --git a/include/cru/common/io/Stream.h b/include/cru/common/io/Stream.h deleted file mode 100644 index e0b61627..00000000 --- a/include/cru/common/io/Stream.h +++ /dev/null @@ -1,126 +0,0 @@ -#pragma once - -#include "../Base.h" - -#include "../Exception.h" -#include "../String.h" - -#include - -namespace cru::io { -class CRU_BASE_API StreamOperationNotSupportedException : public Exception { - public: - explicit StreamOperationNotSupportedException(String operation); - - CRU_DEFAULT_DESTRUCTOR(StreamOperationNotSupportedException) - - public: - String GetOperation() const { return operation_; } - - public: - static void CheckSeek(bool seekable); - static void CheckRead(bool readable); - static void CheckWrite(bool writable); - - private: - String operation_; -}; - -class CRU_BASE_API StreamAlreadyClosedException : public Exception { - public: - StreamAlreadyClosedException(); - - CRU_DEFAULT_DESTRUCTOR(StreamAlreadyClosedException) - - static void Check(bool closed); -}; - -#define CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE \ - void Close() override { DoClose(); } - -#define CRU_STREAM_BEGIN_CLOSE \ - if (GetClosed()) return; \ - CloseGuard close_guard(this); - -/** - * All stream is thread-unsafe by default unless being documented. - */ -class CRU_BASE_API Stream : public Object { - protected: - struct SupportedOperations { - std::optional can_seek; - std::optional can_read; - std::optional can_write; - }; - - struct CloseGuard { - explicit CloseGuard(Stream* stream) : stream(stream) {} - ~CloseGuard() { stream->SetClosed(true); } - Stream* stream; - }; - - protected: - explicit Stream(SupportedOperations supported_operations = {}); - Stream(std::optional can_seek, std::optional can_read, - std::optional can_write); - - public: - enum class SeekOrigin { Current, Begin, End }; - - CRU_DELETE_COPY(Stream) - CRU_DELETE_MOVE(Stream) - - ~Stream() override = default; - - public: - bool CanSeek(); - Index Seek(Index offset, SeekOrigin origin = SeekOrigin::Current); - Index Tell(); - void Rewind(); - Index GetSize(); - - bool CanRead(); - Index Read(std::byte* buffer, Index offset, Index size); - Index Read(std::byte* buffer, Index size); - Index Read(char* buffer, Index offset, Index size); - Index Read(char* buffer, Index size); - - bool CanWrite(); - Index Write(const std::byte* buffer, Index offset, Index size); - Index Write(const std::byte* buffer, Index size); - Index Write(const char* buffer, Index offset, Index size); - Index Write(const char* buffer, Index size); - - void Flush(); - virtual void Close() = 0; - - virtual Buffer ReadToEnd(Index grow_size = 256); - - // Utf8 encoding. - String ReadToEndAsUtf8String(); - - protected: - virtual bool DoCanSeek(); - virtual bool DoCanRead(); - virtual bool DoCanWrite(); - virtual Index DoSeek(Index offset, SeekOrigin origin); - virtual Index DoTell(); - virtual void DoRewind(); - virtual Index DoGetSize(); - virtual Index DoRead(std::byte* buffer, Index offset, Index size); - virtual Index DoWrite(const std::byte* buffer, Index offset, Index size); - virtual void DoFlush(); - - void SetSupportedOperations(SupportedOperations supported_operations) { - supported_operations_ = std::move(supported_operations); - } - - bool GetClosed() { return closed_; } - void SetClosed(bool closed) { closed_ = closed; } - void CheckClosed() { StreamAlreadyClosedException::Check(closed_); } - - private: - std::optional supported_operations_; - bool closed_; -}; -} // namespace cru::io diff --git a/include/cru/common/log/Logger.h b/include/cru/common/log/Logger.h deleted file mode 100644 index 25735e14..00000000 --- a/include/cru/common/log/Logger.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once -#include "../Base.h" - -#include "../Format.h" -#include "../String.h" -#include "../concurrent/ConcurrentQueue.h" - -#include -#include -#include -#include - -namespace cru::log { -enum class LogLevel { Debug, Info, Warn, Error }; - -struct CRU_BASE_API LogInfo { - LogInfo(LogLevel level, String tag, String message) - : level(level), tag(std::move(tag)), message(std::move(message)) {} - - CRU_DEFAULT_COPY(LogInfo) - CRU_DEFAULT_MOVE(LogInfo) - - ~LogInfo() = default; - - LogLevel level; - String tag; - String message; -}; - -struct CRU_BASE_API ILogTarget : virtual Interface { - // Write the string s. LogLevel is just a helper. It has no effect on the - // content to write. - virtual void Write(LogLevel level, StringView s) = 0; -}; - -class CRU_BASE_API Logger : public Object { - public: - static Logger* GetInstance(); - - public: - Logger(); - - CRU_DELETE_COPY(Logger) - CRU_DELETE_MOVE(Logger) - - ~Logger() override; - - public: - void AddLogTarget(std::unique_ptr source); - void RemoveLogTarget(ILogTarget* source); - - public: - void Log(LogLevel level, String tag, String message) { - Log(LogInfo(level, std::move(tag), std::move(message))); - } - void Log(LogInfo log_info); - - template - void FormatLog(LogLevel level, String tag, StringView format, - Args&&... args) { - Log(level, std::move(tag), Format(format, std::forward(args)...)); - } - - private: - concurrent::ConcurrentQueue log_queue_; - - std::mutex target_list_mutex_; - std::vector> target_list_; - - std::thread log_thread_; -}; -} // namespace cru::log - -#define CRU_LOG_DEBUG(...) \ - cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Debug, \ - kLogTag, __VA_ARGS__) - -#define CRU_LOG_INFO(...) \ - cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Info, \ - kLogTag, __VA_ARGS__) - -#define CRU_LOG_WARN(...) \ - cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Warn, \ - kLogTag, __VA_ARGS__) - -#define CRU_LOG_ERROR(...) \ - cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Error, \ - kLogTag, __VA_ARGS__) diff --git a/include/cru/common/log/StdioLogTarget.h b/include/cru/common/log/StdioLogTarget.h deleted file mode 100644 index 4123766b..00000000 --- a/include/cru/common/log/StdioLogTarget.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "Logger.h" - -namespace cru::log { -class StdioLogTarget : public Object, public virtual log::ILogTarget { - public: - explicit StdioLogTarget(); - - CRU_DELETE_COPY(StdioLogTarget) - CRU_DELETE_MOVE(StdioLogTarget) - - ~StdioLogTarget() override; - - public: - void Write(log::LogLevel level, StringView s) override; -}; -} // namespace cru::log diff --git a/include/cru/common/platform/Exception.h b/include/cru/common/platform/Exception.h deleted file mode 100644 index 74dd6ad4..00000000 --- a/include/cru/common/platform/Exception.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../Base.h" -#include "../Exception.h" - -namespace cru::platform { -class CRU_BASE_API PlatformException : public Exception { - public: - using Exception::Exception; // inherit constructors - - CRU_DEFAULT_DESTRUCTOR(PlatformException) -}; -} // namespace cru::platform diff --git a/include/cru/common/platform/osx/Convert.h b/include/cru/common/platform/osx/Convert.h deleted file mode 100644 index 395cbbae..00000000 --- a/include/cru/common/platform/osx/Convert.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "../../PreConfig.h" - -#ifndef CRU_PLATFORM_OSX -#error "This file can only be included on osx." -#endif - -#include "../../String.h" - -#include - -namespace cru::platform::osx { -CFStringRef Convert(const String& string); -String Convert(CFStringRef string); - -CFRange Convert(const Range& range); -Range Convert(const CFRange& range); -} // namespace cru::platform::osx diff --git a/include/cru/common/platform/osx/Exception.h b/include/cru/common/platform/osx/Exception.h deleted file mode 100644 index 5ab14ebd..00000000 --- a/include/cru/common/platform/osx/Exception.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "../../PreConfig.h" - -#ifndef CRU_PLATFORM_OSX -#error "This file can only be included on osx." -#endif - -#include "../Exception.h" - -namespace cru::platform::osx { -class OsxException : public PlatformException { - public: - using PlatformException::PlatformException; -}; -} // namespace cru::platform::osx diff --git a/include/cru/common/platform/unix/PosixSpawnSubProcess.h b/include/cru/common/platform/unix/PosixSpawnSubProcess.h deleted file mode 100644 index ee4e912a..00000000 --- a/include/cru/common/platform/unix/PosixSpawnSubProcess.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "../../PreConfig.h" - -#ifndef CRU_PLATFORM_UNIX -#error "This file can only be included on unix." -#endif - -#include "../../Base.h" -#include "../../SubProcess.h" -#include "../../io/AutoReadStream.h" - -#include "UnixFileStream.h" -#include "UnixPipe.h" - -#include - -namespace cru::platform::unix { -class PosixSpawnSubProcessImpl : public Object, - public virtual IPlatformSubProcessImpl { - CRU_DEFINE_CLASS_LOG_TAG(u"PosixSpawnSubProcess") - - public: - explicit PosixSpawnSubProcessImpl(); - ~PosixSpawnSubProcessImpl(); - - void PlatformCreateProcess(const SubProcessStartInfo& start_info) override; - SubProcessExitResult PlatformWaitForProcess() override; - void PlatformKillProcess() override; - - io::Stream* GetStdinStream() override; - io::Stream* GetStdoutStream() override; - io::Stream* GetStderrStream() override; - - private: - pid_t pid_; - int exit_code_; - - UnixPipe stdin_pipe_; - UnixPipe stdout_pipe_; - UnixPipe stderr_pipe_; - - std::unique_ptr stdin_stream_; - std::unique_ptr stdout_stream_; - std::unique_ptr stderr_stream_; - - std::unique_ptr stdout_buffer_stream_; - std::unique_ptr stderr_buffer_stream_; -}; -} // namespace cru::platform::unix diff --git a/include/cru/common/platform/unix/UnixFileStream.h b/include/cru/common/platform/unix/UnixFileStream.h deleted file mode 100644 index 8021f21a..00000000 --- a/include/cru/common/platform/unix/UnixFileStream.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "../../PreConfig.h" - -#ifndef CRU_PLATFORM_UNIX -#error "This file can only be included on unix." -#endif - -#include "../../io/Stream.h" - -namespace cru::platform::unix { -class UnixFileStream : public io::Stream { - private: - static constexpr auto kLogTag = u"cru::platform::unix::UnixFileStream"; - - public: - UnixFileStream(const char* path, int oflag, mode_t mode = 0660); - UnixFileStream(int fd, bool can_seek, bool can_read, bool can_write, - bool auto_close); - ~UnixFileStream() override; - - public: - CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE - - int GetFileDescriptor() const { return file_descriptor_; } - - protected: - Index DoSeek(Index offset, SeekOrigin origin = SeekOrigin::Current) override; - Index DoRead(std::byte* buffer, Index offset, Index size) override; - Index DoWrite(const std::byte* buffer, Index offset, Index size) override; - - private: - void DoClose(); - - private: - int file_descriptor_; // -1 for no file descriptor - bool auto_close_; -}; -} // namespace cru::platform::unix diff --git a/include/cru/common/platform/unix/UnixPipe.h b/include/cru/common/platform/unix/UnixPipe.h deleted file mode 100644 index cf35fb11..00000000 --- a/include/cru/common/platform/unix/UnixPipe.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include "../../PreConfig.h" - -#ifndef CRU_PLATFORM_UNIX -#error "This file can only be included on unix." -#endif - -#include "../../Base.h" -#include "../../Bitmask.h" - -namespace cru::platform::unix { -namespace details { -struct UnixPipeFlagTag; -} -using UnixPipeFlag = Bitmask; -struct UnixPipeFlags { - constexpr static auto NonBlock = UnixPipeFlag::FromOffset(1); -}; - -/** - * @brief an unix pipe, commonly for communication of parent process and child - * process. - * - * There are two types of pipes sorted by its usage. For stdin, parent process - * SEND data to child process. For stdout and stderr, parent process RECEIVE - * data from child process. Each pipe has two ends, one for read and the other - * for write. But for send and receive, they are reversed. It is a little - * confused to consider which end should be used by parent and which end should - * be used by child. So this class help you make it clear. You specify SEND or - * RECEIVE, and this class give you a parent used end and a child used end. - * - * This class will only close the end used by parent when it is destructed. It - * is the user's duty to close the one used by child. - */ -class UnixPipe : public Object { - private: - constexpr static auto kLogTag = u"cru::platform::unix::UnixPipe"; - - public: - enum class Usage { - Send, - Receive, - }; - - explicit UnixPipe(Usage usage, bool auto_close, UnixPipeFlag flags = {}); - - CRU_DELETE_COPY(UnixPipe) - CRU_DELETE_MOVE(UnixPipe) - - ~UnixPipe(); - - /** - * @brief aka, the one used by parent process. - */ - int GetSelfFileDescriptor(); - - /** - * @brief aka, the one used by child process. - */ - int GetOtherFileDescriptor(); - - private: - Usage usage_; - bool auto_close_; - UnixPipeFlag flags_; - int read_fd_; - int write_fd_; -}; -} // namespace cru::platform::unix diff --git a/include/cru/common/platform/web/WebException.h b/include/cru/common/platform/web/WebException.h deleted file mode 100644 index d98b8943..00000000 --- a/include/cru/common/platform/web/WebException.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "../../PreConfig.h" - -#ifdef CRU_PLATFORM_EMSCRIPTEN - -#include "../Exception.h" - -namespace cru::platform::web { -class WebException : public PlatformException { - public: - using PlatformException::PlatformException; -}; -} // namespace cru::platform::web - -#endif diff --git a/include/cru/common/platform/win/ComAutoInit.h b/include/cru/common/platform/win/ComAutoInit.h deleted file mode 100644 index cc968e4b..00000000 --- a/include/cru/common/platform/win/ComAutoInit.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "../../PreConfig.h" -#ifdef CRU_PLATFORM_WINDOWS - -#include "WinPreConfig.h" -#include "cru/common/Base.h" - -namespace cru::platform::win { -class CRU_BASE_API ComAutoInit { - public: - ComAutoInit(); - - CRU_DELETE_COPY(ComAutoInit) - CRU_DELETE_MOVE(ComAutoInit) - - ~ComAutoInit(); -}; -} // namespace cru::platform::win - -#endif diff --git a/include/cru/common/platform/win/DebugLogTarget.h b/include/cru/common/platform/win/DebugLogTarget.h deleted file mode 100644 index 8257f637..00000000 --- a/include/cru/common/platform/win/DebugLogTarget.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "../../PreConfig.h" -#ifdef CRU_PLATFORM_WINDOWS - -#include "WinPreConfig.h" - -#include "../../log/Logger.h" - -namespace cru::platform::win { - -class CRU_BASE_API WinDebugLogTarget : public ::cru::log::ILogTarget { - public: - WinDebugLogTarget() = default; - - CRU_DELETE_COPY(WinDebugLogTarget) - CRU_DELETE_MOVE(WinDebugLogTarget) - - ~WinDebugLogTarget() = default; - - void Write(::cru::log::LogLevel level, StringView s) override; -}; -} // namespace cru::platform::win - -#endif diff --git a/include/cru/common/platform/win/Exception.h b/include/cru/common/platform/win/Exception.h deleted file mode 100644 index 3e63b191..00000000 --- a/include/cru/common/platform/win/Exception.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include "../../PreConfig.h" -#ifdef CRU_PLATFORM_WINDOWS - -#include "WinPreConfig.h" - -#include "../Exception.h" - -#include -#include - -namespace cru::platform::win { -class CRU_BASE_API HResultError : public platform::PlatformException { - public: - explicit HResultError(HRESULT h_result); - explicit HResultError(HRESULT h_result, std::string_view message); - - CRU_DEFAULT_COPY(HResultError) - CRU_DEFAULT_MOVE(HResultError) - - ~HResultError() override = default; - - HRESULT GetHResult() const { return h_result_; } - - private: - HRESULT h_result_; -}; - -inline void ThrowIfFailed(const HRESULT h_result) { - if (FAILED(h_result)) throw HResultError(h_result); -} - -inline void ThrowIfFailed(const HRESULT h_result, std::string_view message) { - if (FAILED(h_result)) throw HResultError(h_result, message); -} - -class CRU_BASE_API Win32Error : public platform::PlatformException { - public: - // ::GetLastError is automatically called to get the error code. - // The same as Win32Error(::GetLastError(), message) - explicit Win32Error(String message); - Win32Error(DWORD error_code, String message); - - CRU_DEFAULT_COPY(Win32Error) - CRU_DEFAULT_MOVE(Win32Error) - - ~Win32Error() override = default; - - DWORD GetErrorCode() const { return error_code_; } - - private: - DWORD error_code_; -}; -} // namespace cru::platform::win - -#endif diff --git a/include/cru/common/platform/win/StreamConvert.h b/include/cru/common/platform/win/StreamConvert.h deleted file mode 100644 index 3499604a..00000000 --- a/include/cru/common/platform/win/StreamConvert.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "../../PreConfig.h" - -#ifdef CRU_PLATFORM_WINDOWS - -#include "../../io/Stream.h" - -#include - -namespace cru::platform::win { -CRU_BASE_API IStream* ConvertStreamToComStream(io::Stream* stream); -} - -#endif diff --git a/include/cru/common/platform/win/Win32FileStream.h b/include/cru/common/platform/win/Win32FileStream.h deleted file mode 100644 index 06656466..00000000 --- a/include/cru/common/platform/win/Win32FileStream.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "../../PreConfig.h" - -#ifdef CRU_PLATFORM_WINDOWS - -#include "../../String.h" -#include "../../io/OpenFileFlag.h" -#include "../../io/Stream.h" - -namespace cru::platform::win { -namespace details { -class Win32FileStreamPrivate; -} - -class CRU_BASE_API Win32FileStream : public io::Stream { - public: - Win32FileStream(String path, io::OpenFileFlag flags); - - CRU_DELETE_COPY(Win32FileStream) - CRU_DELETE_MOVE(Win32FileStream) - - ~Win32FileStream() override; - - public: - bool CanSeek() override; - Index Seek(Index offset, SeekOrigin origin = SeekOrigin::Current) override; - - bool CanRead() override; - Index Read(std::byte* buffer, Index offset, Index size) override; - using Stream::Read; - - bool CanWrite() override; - Index Write(const std::byte* buffer, Index offset, Index size) override; - using Stream::Write; - - void Close() override; - - String GetPath() const { return path_; } - io::OpenFileFlag GetOpenFileFlags() const { return flags_; } - - details::Win32FileStreamPrivate* GetPrivate_() { return p_; } - - private: - void CheckClosed(); - - private: - String path_; - io::OpenFileFlag flags_; - bool closed_ = false; - - details::Win32FileStreamPrivate* p_; -}; -} // namespace cru::platform::win - -#endif diff --git a/include/cru/common/platform/win/WinPreConfig.h b/include/cru/common/platform/win/WinPreConfig.h deleted file mode 100644 index c2284df3..00000000 --- a/include/cru/common/platform/win/WinPreConfig.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "../../PreConfig.h" -#ifdef CRU_PLATFORM_WINDOWS - -#define NOMINMAX -#define WIN32_LEAN_AND_MEAN -#include -#undef CreateWindow -#undef DrawText -#undef CreateFont -#undef CreateEvent - -#endif diff --git a/include/cru/parse/Production.h b/include/cru/parse/Production.h index d5ababe6..07bd2962 100644 --- a/include/cru/parse/Production.h +++ b/include/cru/parse/Production.h @@ -1,5 +1,5 @@ #pragma once -#include "cru/common/String.h" +#include "cru/base/String.h" #include "Nonterminal.h" #include "Terminal.h" diff --git a/include/cru/parse/Symbol.h b/include/cru/parse/Symbol.h index e7bd4808..0252b3b7 100644 --- a/include/cru/parse/Symbol.h +++ b/include/cru/parse/Symbol.h @@ -1,7 +1,7 @@ #pragma once #include "Base.h" -#include "cru/common/String.h" +#include "cru/base/String.h" namespace cru::parse { class Grammar; diff --git a/include/cru/parse/TokenType.h b/include/cru/parse/TokenType.h index cb6f6159..4e8545b1 100644 --- a/include/cru/parse/TokenType.h +++ b/include/cru/parse/TokenType.h @@ -1,8 +1,8 @@ #pragma once #include "Base.h" -#include "cru/common/Base.h" -#include "cru/common/String.h" +#include "cru/base/Base.h" +#include "cru/base/String.h" namespace cru::parse { class CRU_PARSE_API TokenType : public Object { diff --git a/include/cru/platform/Check.h b/include/cru/platform/Check.h index 453521cc..270150e8 100644 --- a/include/cru/platform/Check.h +++ b/include/cru/platform/Check.h @@ -2,7 +2,7 @@ #include "Exception.h" #include "Resource.h" -#include "cru/common/String.h" +#include "cru/base/String.h" #include #include diff --git a/include/cru/platform/Color.h b/include/cru/platform/Color.h index 2b38138a..d993bd43 100644 --- a/include/cru/platform/Color.h +++ b/include/cru/platform/Color.h @@ -1,9 +1,9 @@ #pragma once #include "Base.h" -#include "cru/common/Base.h" -#include "cru/common/Format.h" -#include "cru/common/String.h" +#include "cru/base/Base.h" +#include "cru/base/Format.h" +#include "cru/base/String.h" #include #include diff --git a/include/cru/platform/Exception.h b/include/cru/platform/Exception.h index a957c95a..2771d4d7 100644 --- a/include/cru/platform/Exception.h +++ b/include/cru/platform/Exception.h @@ -1,8 +1,8 @@ #pragma once #include "Base.h" -#include "cru/common/Base.h" -#include "cru/common/Exception.h" -#include "cru/common/platform/Exception.h" +#include "cru/base/Base.h" +#include "cru/base/Exception.h" +#include "cru/base/platform/Exception.h" #include diff --git a/include/cru/platform/GraphicsBase.h b/include/cru/platform/GraphicsBase.h index 676d3924..4837b08b 100644 --- a/include/cru/platform/GraphicsBase.h +++ b/include/cru/platform/GraphicsBase.h @@ -1,9 +1,9 @@ #pragma once #include "Base.h" -#include "cru/common/Format.h" -#include "cru/common/Range.h" -#include "cru/common/String.h" +#include "cru/base/Format.h" +#include "cru/base/Range.h" +#include "cru/base/String.h" #include diff --git a/include/cru/platform/Resource.h b/include/cru/platform/Resource.h index ba3c5617..69210348 100644 --- a/include/cru/platform/Resource.h +++ b/include/cru/platform/Resource.h @@ -1,8 +1,8 @@ #pragma once #include "Base.h" -#include "cru/common/Base.h" -#include "cru/common/String.h" +#include "cru/base/Base.h" +#include "cru/base/String.h" namespace cru::platform { struct CRU_PLATFORM_API IPlatformResource : virtual Interface { diff --git a/include/cru/platform/graphics/ImageFactory.h b/include/cru/platform/graphics/ImageFactory.h index cd868087..e7e28143 100644 --- a/include/cru/platform/graphics/ImageFactory.h +++ b/include/cru/platform/graphics/ImageFactory.h @@ -1,6 +1,6 @@ #pragma once #include "Resource.h" -#include "cru/common/io/Stream.h" +#include "cru/base/io/Stream.h" namespace cru::platform::graphics { enum class ImageFormat { Jpeg, Png, Gif }; diff --git a/include/cru/platform/graphics/NullPainter.h b/include/cru/platform/graphics/NullPainter.h index 2c6e6cb1..27cb6393 100644 --- a/include/cru/platform/graphics/NullPainter.h +++ b/include/cru/platform/graphics/NullPainter.h @@ -1,6 +1,6 @@ #pragma once #include "Painter.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" namespace cru::platform::graphics { class CRU_PLATFORM_GRAPHICS_API NullPainter : public Object, diff --git a/include/cru/platform/graphics/SvgGeometryBuilderMixin.h b/include/cru/platform/graphics/SvgGeometryBuilderMixin.h index d516ce6c..1f7420e9 100644 --- a/include/cru/platform/graphics/SvgGeometryBuilderMixin.h +++ b/include/cru/platform/graphics/SvgGeometryBuilderMixin.h @@ -1,7 +1,7 @@ #pragma once #include "Geometry.h" -#include "cru/common/Format.h" +#include "cru/base/Format.h" #include diff --git a/include/cru/platform/graphics/direct2d/ComResource.h b/include/cru/platform/graphics/direct2d/ComResource.h index 2beb4e20..d274ae16 100644 --- a/include/cru/platform/graphics/direct2d/ComResource.h +++ b/include/cru/platform/graphics/direct2d/ComResource.h @@ -1,7 +1,7 @@ #pragma once #include "Base.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" namespace cru::platform::graphics::direct2d { template diff --git a/include/cru/platform/graphics/direct2d/Factory.h b/include/cru/platform/graphics/direct2d/Factory.h index d6c43d9f..7abdc31f 100644 --- a/include/cru/platform/graphics/direct2d/Factory.h +++ b/include/cru/platform/graphics/direct2d/Factory.h @@ -3,7 +3,7 @@ #include "ImageFactory.h" -#include "cru/common/platform/win/ComAutoInit.h" +#include "cru/base/platform/win/ComAutoInit.h" #include "cru/platform/graphics/Base.h" #include "cru/platform/graphics/Factory.h" diff --git a/include/cru/platform/graphics/direct2d/Painter.h b/include/cru/platform/graphics/direct2d/Painter.h index f85d840a..5e0fc92f 100644 --- a/include/cru/platform/graphics/direct2d/Painter.h +++ b/include/cru/platform/graphics/direct2d/Painter.h @@ -2,7 +2,7 @@ #include "ComResource.h" #include "Resource.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/graphics/Painter.h" #include diff --git a/include/cru/platform/graphics/quartz/Brush.h b/include/cru/platform/graphics/quartz/Brush.h index d5714293..9b29ef59 100644 --- a/include/cru/platform/graphics/quartz/Brush.h +++ b/include/cru/platform/graphics/quartz/Brush.h @@ -1,6 +1,6 @@ #pragma once #include "Resource.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/graphics/Base.h" #include "cru/platform/graphics/Brush.h" diff --git a/include/cru/platform/graphics/quartz/Convert.h b/include/cru/platform/graphics/quartz/Convert.h index c7dab7c9..c5a1a6cc 100644 --- a/include/cru/platform/graphics/quartz/Convert.h +++ b/include/cru/platform/graphics/quartz/Convert.h @@ -1,7 +1,7 @@ #pragma once -#include "cru/common/Range.h" -#include "cru/common/String.h" -#include "cru/common/io/Stream.h" +#include "cru/base/Range.h" +#include "cru/base/String.h" +#include "cru/base/io/Stream.h" #include "cru/platform/Matrix.h" #include diff --git a/include/cru/platform/graphics/quartz/Factory.h b/include/cru/platform/graphics/quartz/Factory.h index 57992d87..042e35ca 100644 --- a/include/cru/platform/graphics/quartz/Factory.h +++ b/include/cru/platform/graphics/quartz/Factory.h @@ -1,6 +1,6 @@ #pragma once #include "Resource.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/graphics/quartz/ImageFactory.h" #include "cru/platform/graphics/Factory.h" #include "cru/platform/graphics/ImageFactory.h" diff --git a/include/cru/platform/graphics/quartz/Font.h b/include/cru/platform/graphics/quartz/Font.h index 36dba31a..975607b9 100644 --- a/include/cru/platform/graphics/quartz/Font.h +++ b/include/cru/platform/graphics/quartz/Font.h @@ -1,6 +1,6 @@ #pragma once #include "Resource.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/graphics/Font.h" #include diff --git a/include/cru/platform/graphics/quartz/Painter.h b/include/cru/platform/graphics/quartz/Painter.h index eba66a56..9e21904d 100644 --- a/include/cru/platform/graphics/quartz/Painter.h +++ b/include/cru/platform/graphics/quartz/Painter.h @@ -1,6 +1,6 @@ #pragma once #include "Resource.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/graphics/Base.h" #include "cru/platform/graphics/Painter.h" diff --git a/include/cru/platform/graphics/quartz/TextLayout.h b/include/cru/platform/graphics/quartz/TextLayout.h index 0d23360d..bbb417f6 100644 --- a/include/cru/platform/graphics/quartz/TextLayout.h +++ b/include/cru/platform/graphics/quartz/TextLayout.h @@ -2,7 +2,7 @@ #include "Resource.h" #include "Font.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/graphics/TextLayout.h" #include diff --git a/include/cru/platform/graphics/web_canvas/WebCanvasRef.h b/include/cru/platform/graphics/web_canvas/WebCanvasRef.h index a5d4f395..a8995b90 100644 --- a/include/cru/platform/graphics/web_canvas/WebCanvasRef.h +++ b/include/cru/platform/graphics/web_canvas/WebCanvasRef.h @@ -1,6 +1,6 @@ #pragma once -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include diff --git a/include/cru/platform/graphics/web_canvas/WebCanvasResource.h b/include/cru/platform/graphics/web_canvas/WebCanvasResource.h index 1e9bf75d..6c8087d0 100644 --- a/include/cru/platform/graphics/web_canvas/WebCanvasResource.h +++ b/include/cru/platform/graphics/web_canvas/WebCanvasResource.h @@ -1,6 +1,6 @@ #pragma once -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/Resource.h" namespace cru::platform::graphics::web_canvas { diff --git a/include/cru/platform/gui/Base.h b/include/cru/platform/gui/Base.h index 789ab308..f84e815e 100644 --- a/include/cru/platform/gui/Base.h +++ b/include/cru/platform/gui/Base.h @@ -1,6 +1,6 @@ #pragma once -#include "cru/common/Base.h" -#include "cru/common/Bitmask.h" +#include "cru/base/Base.h" +#include "cru/base/Bitmask.h" #include "cru/platform/graphics/Base.h" #include "../Resource.h" diff --git a/include/cru/platform/gui/InputMethod.h b/include/cru/platform/gui/InputMethod.h index 90d6b15a..b4a1e9d9 100644 --- a/include/cru/platform/gui/InputMethod.h +++ b/include/cru/platform/gui/InputMethod.h @@ -1,7 +1,7 @@ #pragma once #include "Base.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include #include diff --git a/include/cru/platform/gui/Keyboard.h b/include/cru/platform/gui/Keyboard.h index f25b25fa..224aea04 100644 --- a/include/cru/platform/gui/Keyboard.h +++ b/include/cru/platform/gui/Keyboard.h @@ -1,5 +1,5 @@ #pragma once -#include "cru/common/Bitmask.h" +#include "cru/base/Bitmask.h" #include "cru/platform/gui/Base.h" #include diff --git a/include/cru/platform/gui/UiApplication.h b/include/cru/platform/gui/UiApplication.h index ef13aaa4..88aa3e20 100644 --- a/include/cru/platform/gui/UiApplication.h +++ b/include/cru/platform/gui/UiApplication.h @@ -1,7 +1,7 @@ #pragma once #include "Base.h" -#include "cru/common/Bitmask.h" +#include "cru/base/Bitmask.h" #include "cru/platform/gui/Menu.h" #include "SaveOpenDialogOptions.h" diff --git a/include/cru/platform/gui/Window.h b/include/cru/platform/gui/Window.h index d3f0daad..7f6923d1 100644 --- a/include/cru/platform/gui/Window.h +++ b/include/cru/platform/gui/Window.h @@ -3,7 +3,7 @@ #include "Keyboard.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include diff --git a/include/cru/platform/gui/win/Base.h b/include/cru/platform/gui/win/Base.h index 78068827..d9a81068 100644 --- a/include/cru/platform/gui/win/Base.h +++ b/include/cru/platform/gui/win/Base.h @@ -1,7 +1,7 @@ #pragma once #include "cru/platform/win/WinPreConfig.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #ifdef CRU_PLATFORM_WINDOWS #ifdef CRU_WIN_GUI_EXPORT_API diff --git a/include/cru/platform/gui/win/Clipboard.h b/include/cru/platform/gui/win/Clipboard.h index dc4bc9b5..a322d520 100644 --- a/include/cru/platform/gui/win/Clipboard.h +++ b/include/cru/platform/gui/win/Clipboard.h @@ -1,6 +1,6 @@ #pragma once #include "Resource.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/gui/Clipboard.h" #include "cru/platform/gui/win/Base.h" diff --git a/include/cru/platform/gui/win/GodWindow.h b/include/cru/platform/gui/win/GodWindow.h index fe61c80d..84fdfcea 100644 --- a/include/cru/platform/gui/win/GodWindow.h +++ b/include/cru/platform/gui/win/GodWindow.h @@ -2,8 +2,8 @@ #include "Base.h" #include "WindowNativeMessageEventArgs.h" -#include "cru/common/Event.h" -#include "cru/common/String.h" +#include "cru/base/Event.h" +#include "cru/base/String.h" #include diff --git a/include/cru/platform/gui/win/WindowNativeMessageEventArgs.h b/include/cru/platform/gui/win/WindowNativeMessageEventArgs.h index bc85a597..1b5a233c 100644 --- a/include/cru/platform/gui/win/WindowNativeMessageEventArgs.h +++ b/include/cru/platform/gui/win/WindowNativeMessageEventArgs.h @@ -1,7 +1,7 @@ #pragma once #include "Base.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" namespace cru::platform::gui::win { struct CRU_WIN_GUI_API WindowNativeMessage { diff --git a/include/cru/platform/osx/Convert.h b/include/cru/platform/osx/Convert.h index bf32174a..7994af44 100644 --- a/include/cru/platform/osx/Convert.h +++ b/include/cru/platform/osx/Convert.h @@ -1,2 +1,2 @@ #pragma once -#include "cru/common/platform/osx/Convert.h" +#include "cru/base/platform/osx/Convert.h" diff --git a/include/cru/platform/osx/Exception.h b/include/cru/platform/osx/Exception.h index c346b970..d3c2aee0 100644 --- a/include/cru/platform/osx/Exception.h +++ b/include/cru/platform/osx/Exception.h @@ -1,3 +1,3 @@ #pragma once -#include "cru/common/platform/osx/Exception.h" +#include "cru/base/platform/osx/Exception.h" #include "cru/platform/Exception.h" diff --git a/include/cru/platform/win/Exception.h b/include/cru/platform/win/Exception.h index af8b495c..353c2dab 100644 --- a/include/cru/platform/win/Exception.h +++ b/include/cru/platform/win/Exception.h @@ -1,3 +1,3 @@ #pragma once -#include "cru/common/platform/win/Exception.h" +#include "cru/base/platform/win/Exception.h" #include "cru/platform/Exception.h" diff --git a/include/cru/platform/win/WinPreConfig.h b/include/cru/platform/win/WinPreConfig.h index e714bf5e..a67faf8f 100644 --- a/include/cru/platform/win/WinPreConfig.h +++ b/include/cru/platform/win/WinPreConfig.h @@ -1,2 +1,2 @@ #pragma once -#include "cru/common/platform/win/WinPreConfig.h" +#include "cru/base/platform/win/WinPreConfig.h" diff --git a/include/cru/toml/TomlDocument.h b/include/cru/toml/TomlDocument.h index 6da5ad74..d072d384 100644 --- a/include/cru/toml/TomlDocument.h +++ b/include/cru/toml/TomlDocument.h @@ -2,8 +2,8 @@ #include "Base.h" -#include "cru/common/Base.h" -#include "cru/common/String.h" +#include "cru/base/Base.h" +#include "cru/base/String.h" #include #include diff --git a/include/cru/toml/TomlParser.h b/include/cru/toml/TomlParser.h index dcef2920..76c270c3 100644 --- a/include/cru/toml/TomlParser.h +++ b/include/cru/toml/TomlParser.h @@ -1,6 +1,6 @@ #pragma once -#include "cru/common/Exception.h" +#include "cru/base/Exception.h" #include "cru/toml/TomlDocument.h" #include diff --git a/include/cru/ui/Base.h b/include/cru/ui/Base.h index 5e62d785..78b8ccf9 100644 --- a/include/cru/ui/Base.h +++ b/include/cru/ui/Base.h @@ -1,5 +1,5 @@ #pragma once -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/graphics/Base.h" #include "cru/platform/gui/Base.h" diff --git a/include/cru/ui/ThemeManager.h b/include/cru/ui/ThemeManager.h index faa8a1cf..d4e6a096 100644 --- a/include/cru/ui/ThemeManager.h +++ b/include/cru/ui/ThemeManager.h @@ -1,6 +1,6 @@ #pragma once #include "Base.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/ui/ThemeResourceDictionary.h" #include diff --git a/include/cru/ui/ThemeResourceDictionary.h b/include/cru/ui/ThemeResourceDictionary.h index 7112ab27..597fe707 100644 --- a/include/cru/ui/ThemeResourceDictionary.h +++ b/include/cru/ui/ThemeResourceDictionary.h @@ -1,7 +1,7 @@ #pragma once #include "Base.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/xml/XmlNode.h" #include "mapper/MapperRegistry.h" #include "style/StyleRuleSet.h" diff --git a/include/cru/ui/components/Component.h b/include/cru/ui/components/Component.h index a2f83149..ae742aae 100644 --- a/include/cru/ui/components/Component.h +++ b/include/cru/ui/components/Component.h @@ -1,7 +1,7 @@ #pragma once #include "../Base.h" #include "../DeleteLater.h" -#include "cru/common/SelfResolvable.h" +#include "cru/base/SelfResolvable.h" namespace cru::ui::components { /** diff --git a/include/cru/ui/components/Menu.h b/include/cru/ui/components/Menu.h index 82766aa5..913f5c92 100644 --- a/include/cru/ui/components/Menu.h +++ b/include/cru/ui/components/Menu.h @@ -1,6 +1,6 @@ #pragma once #include "Component.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/ui/controls/Button.h" #include "cru/ui/controls/Control.h" #include "cru/ui/controls/FlexLayout.h" diff --git a/include/cru/ui/controls/Button.h b/include/cru/ui/controls/Button.h index 6df23c62..717710e8 100644 --- a/include/cru/ui/controls/Button.h +++ b/include/cru/ui/controls/Button.h @@ -5,7 +5,7 @@ #include "../render/BorderRenderObject.h" #include "IBorderControl.h" #include "IClickableControl.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" namespace cru::ui::controls { class CRU_UI_API Button : public SingleChildControl, diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h index 38a9a86b..790f4a3a 100644 --- a/include/cru/ui/controls/Control.h +++ b/include/cru/ui/controls/Control.h @@ -4,7 +4,7 @@ #include "../events/UiEvents.h" #include "../render/RenderObject.h" #include "../style/StyleRuleSet.h" -#include "cru/common/SelfResolvable.h" +#include "cru/base/SelfResolvable.h" #include "cru/ui/render/MeasureRequirement.h" namespace cru::ui::controls { diff --git a/include/cru/ui/controls/IBorderControl.h b/include/cru/ui/controls/IBorderControl.h index f8f2f88d..e3eb3388 100644 --- a/include/cru/ui/controls/IBorderControl.h +++ b/include/cru/ui/controls/IBorderControl.h @@ -1,6 +1,6 @@ #pragma once #include "../style/ApplyBorderStyleInfo.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" namespace cru::ui::controls { struct CRU_UI_API IBorderControl : virtual Interface { diff --git a/include/cru/ui/controls/ICheckableControl.h b/include/cru/ui/controls/ICheckableControl.h index 2c7aace8..7a6d7b8e 100644 --- a/include/cru/ui/controls/ICheckableControl.h +++ b/include/cru/ui/controls/ICheckableControl.h @@ -1,6 +1,6 @@ #pragma once #include "../Base.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" namespace cru::ui::controls { struct CRU_UI_API ICheckableControl : virtual Interface { diff --git a/include/cru/ui/controls/IClickableControl.h b/include/cru/ui/controls/IClickableControl.h index 67fa43ab..4ddea730 100644 --- a/include/cru/ui/controls/IClickableControl.h +++ b/include/cru/ui/controls/IClickableControl.h @@ -1,7 +1,7 @@ #pragma once #include "../helper/ClickDetector.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" namespace cru::ui::controls { struct CRU_UI_API IClickableControl : virtual Interface { diff --git a/include/cru/ui/controls/IconButton.h b/include/cru/ui/controls/IconButton.h index a76d01d4..632450e2 100644 --- a/include/cru/ui/controls/IconButton.h +++ b/include/cru/ui/controls/IconButton.h @@ -8,7 +8,7 @@ #include "IBorderControl.h" #include "IClickableControl.h" #include "IContentBrushControl.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/platform/graphics/Brush.h" namespace cru::ui::controls { diff --git a/include/cru/ui/controls/RootControl.h b/include/cru/ui/controls/RootControl.h index 851b4db0..5fa8090e 100644 --- a/include/cru/ui/controls/RootControl.h +++ b/include/cru/ui/controls/RootControl.h @@ -1,7 +1,7 @@ #pragma once #include "LayoutControl.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/platform/gui/Window.h" #include "cru/ui/host/WindowHost.h" #include "cru/ui/render/StackLayoutRenderObject.h" diff --git a/include/cru/ui/controls/Window.h b/include/cru/ui/controls/Window.h index a1a97f87..656a96dd 100644 --- a/include/cru/ui/controls/Window.h +++ b/include/cru/ui/controls/Window.h @@ -2,7 +2,7 @@ #include "cru/platform/gui/Base.h" #include "cru/ui/controls/RootControl.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" namespace cru::ui::controls { class CRU_UI_API Window final : public RootControl { diff --git a/include/cru/ui/document/DocumentElementType.h b/include/cru/ui/document/DocumentElementType.h index d16836c1..6d4958d0 100644 --- a/include/cru/ui/document/DocumentElementType.h +++ b/include/cru/ui/document/DocumentElementType.h @@ -1,7 +1,7 @@ #pragma once #include "../Base.h" -#include "cru/common/String.h" +#include "cru/base/String.h" #include diff --git a/include/cru/ui/document/TextDocumentElement.h b/include/cru/ui/document/TextDocumentElement.h index 93b4933b..73a041ef 100644 --- a/include/cru/ui/document/TextDocumentElement.h +++ b/include/cru/ui/document/TextDocumentElement.h @@ -2,8 +2,8 @@ #include "../Base.h" #include "DocumentElement.h" -#include "cru/common/Base.h" -#include "cru/common/Bitmask.h" +#include "cru/base/Base.h" +#include "cru/base/Bitmask.h" namespace cru::ui::document { namespace details { diff --git a/include/cru/ui/events/RoutedEvent.h b/include/cru/ui/events/RoutedEvent.h index 909678f8..a01839a6 100644 --- a/include/cru/ui/events/RoutedEvent.h +++ b/include/cru/ui/events/RoutedEvent.h @@ -1,7 +1,7 @@ #pragma once #include "UiEventArgs.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" namespace cru::ui::events { // TEventArgs must not be a reference type. This class help add reference. diff --git a/include/cru/ui/helper/ClickDetector.h b/include/cru/ui/helper/ClickDetector.h index 3bf28451..5e30d9c3 100644 --- a/include/cru/ui/helper/ClickDetector.h +++ b/include/cru/ui/helper/ClickDetector.h @@ -1,7 +1,7 @@ #pragma once #include "../Base.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" namespace cru::ui::helper { class ClickDetector; diff --git a/include/cru/ui/helper/ShortcutHub.h b/include/cru/ui/helper/ShortcutHub.h index fe3b2a72..341e76da 100644 --- a/include/cru/ui/helper/ShortcutHub.h +++ b/include/cru/ui/helper/ShortcutHub.h @@ -2,8 +2,8 @@ #include "../Base.h" #include "../events/KeyEventArgs.h" -#include "cru/common/Base.h" -#include "cru/common/Event.h" +#include "cru/base/Base.h" +#include "cru/base/Event.h" #include "cru/platform/gui/Keyboard.h" #include diff --git a/include/cru/ui/host/WindowHost.h b/include/cru/ui/host/WindowHost.h index 17f69d89..23229036 100644 --- a/include/cru/ui/host/WindowHost.h +++ b/include/cru/ui/host/WindowHost.h @@ -2,7 +2,7 @@ #include "../Base.h" #include "../render/RenderObject.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/platform/gui/Cursor.h" #include "cru/platform/gui/UiApplication.h" #include "cru/platform/gui/Window.h" diff --git a/include/cru/ui/mapper/BrushMapper.h b/include/cru/ui/mapper/BrushMapper.h index 0748c037..3b918dc7 100644 --- a/include/cru/ui/mapper/BrushMapper.h +++ b/include/cru/ui/mapper/BrushMapper.h @@ -1,6 +1,6 @@ #pragma once #include "Mapper.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/graphics/Brush.h" #include "cru/xml/XmlNode.h" diff --git a/include/cru/ui/mapper/FontMapper.h b/include/cru/ui/mapper/FontMapper.h index f6dbf56a..f8b10047 100644 --- a/include/cru/ui/mapper/FontMapper.h +++ b/include/cru/ui/mapper/FontMapper.h @@ -1,6 +1,6 @@ #pragma once #include "Mapper.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/graphics/Font.h" namespace cru::ui::mapper { diff --git a/include/cru/ui/mapper/Mapper.h b/include/cru/ui/mapper/Mapper.h index e059f9c0..40e15186 100644 --- a/include/cru/ui/mapper/Mapper.h +++ b/include/cru/ui/mapper/Mapper.h @@ -1,8 +1,8 @@ #pragma once #include "../Base.h" -#include "cru/common/ClonablePtr.h" -#include "cru/common/Exception.h" +#include "cru/base/ClonablePtr.h" +#include "cru/base/Exception.h" #include "cru/xml/XmlNode.h" #include diff --git a/include/cru/ui/mapper/ThicknessMapper.h b/include/cru/ui/mapper/ThicknessMapper.h index 10f6c87e..fab1e5d3 100644 --- a/include/cru/ui/mapper/ThicknessMapper.h +++ b/include/cru/ui/mapper/ThicknessMapper.h @@ -2,7 +2,7 @@ #include "Mapper.h" #include "../Base.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/xml/XmlNode.h" namespace cru::ui::mapper { diff --git a/include/cru/ui/mapper/style/BorderStylerMapper.h b/include/cru/ui/mapper/style/BorderStylerMapper.h index 3cf78faa..57b5dce4 100644 --- a/include/cru/ui/mapper/style/BorderStylerMapper.h +++ b/include/cru/ui/mapper/style/BorderStylerMapper.h @@ -1,6 +1,6 @@ #pragma once #include "../Mapper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/mapper/style/IStylerMapper.h" #include "cru/ui/style/Styler.h" #include "cru/xml/XmlNode.h" diff --git a/include/cru/ui/mapper/style/IConditionMapper.h b/include/cru/ui/mapper/style/IConditionMapper.h index 7610dc8d..bfe24224 100644 --- a/include/cru/ui/mapper/style/IConditionMapper.h +++ b/include/cru/ui/mapper/style/IConditionMapper.h @@ -1,6 +1,6 @@ #pragma once #include "../../Base.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/mapper/Mapper.h" #include "cru/ui/style/Condition.h" #include "cru/xml/XmlNode.h" diff --git a/include/cru/ui/mapper/style/IStylerMapper.h b/include/cru/ui/mapper/style/IStylerMapper.h index 4c2ecd16..adf9b6fb 100644 --- a/include/cru/ui/mapper/style/IStylerMapper.h +++ b/include/cru/ui/mapper/style/IStylerMapper.h @@ -1,6 +1,6 @@ #pragma once #include "../../Base.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/mapper/Mapper.h" #include "cru/ui/style/Styler.h" #include "cru/xml/XmlNode.h" diff --git a/include/cru/ui/mapper/style/NoConditionMapper.h b/include/cru/ui/mapper/style/NoConditionMapper.h index 2103a268..06106514 100644 --- a/include/cru/ui/mapper/style/NoConditionMapper.h +++ b/include/cru/ui/mapper/style/NoConditionMapper.h @@ -1,8 +1,8 @@ #pragma once #include "../Mapper.h" #include "IConditionMapper.h" -#include "cru/common/Base.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/Base.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Condition.h" #include "cru/xml/XmlNode.h" diff --git a/include/cru/ui/mapper/style/StyleRuleMapper.h b/include/cru/ui/mapper/style/StyleRuleMapper.h index 21bf3176..7430274c 100644 --- a/include/cru/ui/mapper/style/StyleRuleMapper.h +++ b/include/cru/ui/mapper/style/StyleRuleMapper.h @@ -1,7 +1,7 @@ #pragma once #include "../Mapper.h" -#include "cru/common/Base.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/Base.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/StyleRule.h" #include "cru/xml/XmlNode.h" diff --git a/include/cru/ui/model/IListChangeNotify.h b/include/cru/ui/model/IListChangeNotify.h index a9fcd65b..0cbd25f2 100644 --- a/include/cru/ui/model/IListChangeNotify.h +++ b/include/cru/ui/model/IListChangeNotify.h @@ -1,7 +1,7 @@ #pragma once #include "../Base.h" -#include "cru/common/Base.h" -#include "cru/common/Event.h" +#include "cru/base/Base.h" +#include "cru/base/Event.h" namespace cru::ui::model { enum ListChangeType { diff --git a/include/cru/ui/render/CanvasRenderObject.h b/include/cru/ui/render/CanvasRenderObject.h index f498c5ae..dfe8f090 100644 --- a/include/cru/ui/render/CanvasRenderObject.h +++ b/include/cru/ui/render/CanvasRenderObject.h @@ -1,7 +1,7 @@ #pragma once #include "RenderObject.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" namespace cru::ui::render { class CanvasPaintEventArgs { diff --git a/include/cru/ui/render/MeasureRequirement.h b/include/cru/ui/render/MeasureRequirement.h index ace52ef6..3f4e0a3d 100644 --- a/include/cru/ui/render/MeasureRequirement.h +++ b/include/cru/ui/render/MeasureRequirement.h @@ -1,7 +1,7 @@ #pragma once #include "../Base.h" -#include "cru/common/String.h" +#include "cru/base/String.h" #include #include diff --git a/include/cru/ui/render/RenderObject.h b/include/cru/ui/render/RenderObject.h index 8a0ba511..7ab62446 100644 --- a/include/cru/ui/render/RenderObject.h +++ b/include/cru/ui/render/RenderObject.h @@ -2,7 +2,7 @@ #include "../Base.h" #include "MeasureRequirement.h" -#include "cru/common/String.h" +#include "cru/base/String.h" namespace cru::ui::render { struct BoxConstraint { diff --git a/include/cru/ui/render/ScrollBar.h b/include/cru/ui/render/ScrollBar.h index 20b6e6cf..45f80389 100644 --- a/include/cru/ui/render/ScrollBar.h +++ b/include/cru/ui/render/ScrollBar.h @@ -1,6 +1,6 @@ #pragma once -#include "cru/common/Base.h" -#include "cru/common/Event.h" +#include "cru/base/Base.h" +#include "cru/base/Event.h" #include "cru/platform/graphics/Base.h" #include "cru/platform/graphics/Brush.h" #include "cru/platform/graphics/Geometry.h" diff --git a/include/cru/ui/render/ScrollRenderObject.h b/include/cru/ui/render/ScrollRenderObject.h index 44656942..180e927a 100644 --- a/include/cru/ui/render/ScrollRenderObject.h +++ b/include/cru/ui/render/ScrollRenderObject.h @@ -2,7 +2,7 @@ #include "SingleChildRenderObject.h" #include "ScrollBar.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/ui/render/RenderObject.h" #include diff --git a/include/cru/ui/style/Condition.h b/include/cru/ui/style/Condition.h index 28f42315..2d2dceac 100644 --- a/include/cru/ui/style/Condition.h +++ b/include/cru/ui/style/Condition.h @@ -1,8 +1,8 @@ #pragma once #include "../Base.h" -#include "cru/common/Base.h" -#include "cru/common/ClonablePtr.h" -#include "cru/common/Event.h" +#include "cru/base/Base.h" +#include "cru/base/ClonablePtr.h" +#include "cru/base/Event.h" #include "cru/ui/controls/IClickableControl.h" #include "cru/ui/helper/ClickDetector.h" diff --git a/include/cru/ui/style/StyleRule.h b/include/cru/ui/style/StyleRule.h index 27069930..1ae2f0f1 100644 --- a/include/cru/ui/style/StyleRule.h +++ b/include/cru/ui/style/StyleRule.h @@ -2,7 +2,7 @@ #include "../Base.h" #include "Condition.h" #include "Styler.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include #include diff --git a/include/cru/ui/style/StyleRuleSet.h b/include/cru/ui/style/StyleRuleSet.h index 080c2eb8..fae9ab5f 100644 --- a/include/cru/ui/style/StyleRuleSet.h +++ b/include/cru/ui/style/StyleRuleSet.h @@ -1,7 +1,7 @@ #pragma once #include "StyleRule.h" -#include "cru/common/Base.h" -#include "cru/common/Event.h" +#include "cru/base/Base.h" +#include "cru/base/Event.h" #include "cru/ui/model/IListChangeNotify.h" #include diff --git a/include/cru/ui/style/Styler.h b/include/cru/ui/style/Styler.h index 7df3e138..3ed85e1e 100644 --- a/include/cru/ui/style/Styler.h +++ b/include/cru/ui/style/Styler.h @@ -1,7 +1,7 @@ #pragma once #include "../Base.h" #include "ApplyBorderStyleInfo.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/platform/graphics/Brush.h" #include "cru/platform/gui/Cursor.h" #include "cru/ui/render/MeasureRequirement.h" diff --git a/include/cru/xml/XmlNode.h b/include/cru/xml/XmlNode.h index 50685749..a7d1bf38 100644 --- a/include/cru/xml/XmlNode.h +++ b/include/cru/xml/XmlNode.h @@ -2,7 +2,7 @@ #include "Base.h" -#include "cru/common/String.h" +#include "cru/base/String.h" #include #include diff --git a/include/cru/xml/XmlParser.h b/include/cru/xml/XmlParser.h index 75664ce3..ca4fb54a 100644 --- a/include/cru/xml/XmlParser.h +++ b/include/cru/xml/XmlParser.h @@ -2,8 +2,8 @@ #include "XmlNode.h" -#include "cru/common/Exception.h" -#include "cru/common/String.h" +#include "cru/base/Exception.h" +#include "cru/base/String.h" #include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9cb01e47..959f2dd1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,5 @@ -add_subdirectory(common) - +add_subdirectory(base) add_subdirectory(platform) - add_subdirectory(ui) add_subdirectory(parse) add_subdirectory(toml) diff --git a/src/ThemeBuilder/components/Editor.h b/src/ThemeBuilder/components/Editor.h index 29809c82..2e1db741 100644 --- a/src/ThemeBuilder/components/Editor.h +++ b/src/ThemeBuilder/components/Editor.h @@ -1,5 +1,5 @@ #pragma once -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/ui/components/Component.h" namespace cru::theme_builder::components { diff --git a/src/ThemeBuilder/components/HeadBodyEditor.h b/src/ThemeBuilder/components/HeadBodyEditor.h index 8119724f..1fcf2f63 100644 --- a/src/ThemeBuilder/components/HeadBodyEditor.h +++ b/src/ThemeBuilder/components/HeadBodyEditor.h @@ -1,6 +1,6 @@ #pragma once #include "Editor.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/ui/controls/Container.h" #include "cru/ui/controls/FlexLayout.h" #include "cru/ui/controls/IconButton.h" diff --git a/src/ThemeBuilder/components/StyleRuleSetEditor.cpp b/src/ThemeBuilder/components/StyleRuleSetEditor.cpp index 8cf5af6d..a1c19e08 100644 --- a/src/ThemeBuilder/components/StyleRuleSetEditor.cpp +++ b/src/ThemeBuilder/components/StyleRuleSetEditor.cpp @@ -1,6 +1,6 @@ #include "StyleRuleSetEditor.h" -#include "cru/common/Exception.h" -#include "cru/common/String.h" +#include "cru/base/Exception.h" +#include "cru/base/String.h" #include "cru/ui/DeleteLater.h" #include "cru/ui/ThemeManager.h" #include "cru/ui/controls/FlexLayout.h" diff --git a/src/ThemeBuilder/components/conditions/CheckedConditionEditor.cpp b/src/ThemeBuilder/components/conditions/CheckedConditionEditor.cpp index 64370981..57e72a0f 100644 --- a/src/ThemeBuilder/components/conditions/CheckedConditionEditor.cpp +++ b/src/ThemeBuilder/components/conditions/CheckedConditionEditor.cpp @@ -1,5 +1,5 @@ #include "CheckedConditionEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Condition.h" namespace cru::theme_builder::components::conditions { diff --git a/src/ThemeBuilder/components/conditions/CheckedConditionEditor.h b/src/ThemeBuilder/components/conditions/CheckedConditionEditor.h index 7cf14912..b6e740f1 100644 --- a/src/ThemeBuilder/components/conditions/CheckedConditionEditor.h +++ b/src/ThemeBuilder/components/conditions/CheckedConditionEditor.h @@ -1,7 +1,7 @@ #pragma once #include "../properties/CheckBoxPropertyEditor.h" #include "ConditionEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Condition.h" namespace cru::theme_builder::components::conditions { diff --git a/src/ThemeBuilder/components/conditions/ClickStateConditionEditor.cpp b/src/ThemeBuilder/components/conditions/ClickStateConditionEditor.cpp index a8d5cc87..bf0b1d98 100644 --- a/src/ThemeBuilder/components/conditions/ClickStateConditionEditor.cpp +++ b/src/ThemeBuilder/components/conditions/ClickStateConditionEditor.cpp @@ -1,5 +1,5 @@ #include "ClickStateConditionEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/helper/ClickDetector.h" #include "cru/ui/style/Condition.h" diff --git a/src/ThemeBuilder/components/conditions/ClickStateConditionEditor.h b/src/ThemeBuilder/components/conditions/ClickStateConditionEditor.h index 454a1346..2ea4fcf4 100644 --- a/src/ThemeBuilder/components/conditions/ClickStateConditionEditor.h +++ b/src/ThemeBuilder/components/conditions/ClickStateConditionEditor.h @@ -1,8 +1,8 @@ #pragma once #include "../properties/SelectPropertyEditor.h" #include "ConditionEditor.h" -#include "cru/common/ClonablePtr.h" -#include "cru/common/Event.h" +#include "cru/base/ClonablePtr.h" +#include "cru/base/Event.h" #include "cru/ui/style/Condition.h" namespace cru::theme_builder::components::conditions { diff --git a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp index 69b8ed02..8be3aa0f 100644 --- a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp +++ b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp @@ -4,7 +4,7 @@ #include "ConditionEditor.h" #include "FocusConditionEditor.h" #include "NoConditionEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/platform/Color.h" #include "cru/ui/Base.h" #include "cru/ui/ThemeManager.h" diff --git a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.h b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.h index e1398514..2948df36 100644 --- a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.h +++ b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.h @@ -1,7 +1,7 @@ #pragma once #include "ConditionEditor.h" -#include "cru/common/ClonablePtr.h" -#include "cru/common/Event.h" +#include "cru/base/ClonablePtr.h" +#include "cru/base/Event.h" #include "cru/ui/components/Component.h" #include "cru/ui/components/PopupButton.h" #include "cru/ui/controls/Button.h" diff --git a/src/ThemeBuilder/components/conditions/ConditionEditor.cpp b/src/ThemeBuilder/components/conditions/ConditionEditor.cpp index 5b79c639..421bb028 100644 --- a/src/ThemeBuilder/components/conditions/ConditionEditor.cpp +++ b/src/ThemeBuilder/components/conditions/ConditionEditor.cpp @@ -5,7 +5,7 @@ #include "CompoundConditionEditor.h" #include "FocusConditionEditor.h" #include "NoConditionEditor.h" -#include "cru/common/Exception.h" +#include "cru/base/Exception.h" #include "cru/ui/controls/FlexLayout.h" namespace cru::theme_builder::components::conditions { diff --git a/src/ThemeBuilder/components/conditions/FocusConditionEditor.cpp b/src/ThemeBuilder/components/conditions/FocusConditionEditor.cpp index 1fb99d64..78c99b5c 100644 --- a/src/ThemeBuilder/components/conditions/FocusConditionEditor.cpp +++ b/src/ThemeBuilder/components/conditions/FocusConditionEditor.cpp @@ -1,5 +1,5 @@ #include "FocusConditionEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Condition.h" namespace cru::theme_builder::components::conditions { diff --git a/src/ThemeBuilder/components/conditions/FocusConditionEditor.h b/src/ThemeBuilder/components/conditions/FocusConditionEditor.h index 1faf4d7d..d5478653 100644 --- a/src/ThemeBuilder/components/conditions/FocusConditionEditor.h +++ b/src/ThemeBuilder/components/conditions/FocusConditionEditor.h @@ -1,7 +1,7 @@ #pragma once #include "../properties/CheckBoxPropertyEditor.h" #include "ConditionEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Condition.h" namespace cru::theme_builder::components::conditions { diff --git a/src/ThemeBuilder/components/conditions/NoConditionEditor.h b/src/ThemeBuilder/components/conditions/NoConditionEditor.h index 19616319..b38806b5 100644 --- a/src/ThemeBuilder/components/conditions/NoConditionEditor.h +++ b/src/ThemeBuilder/components/conditions/NoConditionEditor.h @@ -1,6 +1,6 @@ #pragma once #include "ConditionEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Condition.h" namespace cru::theme_builder::components::conditions { diff --git a/src/ThemeBuilder/components/properties/MeasureLengthPropertyEditor.cpp b/src/ThemeBuilder/components/properties/MeasureLengthPropertyEditor.cpp index d1f4afce..ad338e78 100644 --- a/src/ThemeBuilder/components/properties/MeasureLengthPropertyEditor.cpp +++ b/src/ThemeBuilder/components/properties/MeasureLengthPropertyEditor.cpp @@ -1,5 +1,5 @@ #include "MeasureLengthPropertyEditor.h" -#include "cru/common/Format.h" +#include "cru/base/Format.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/render/MeasureRequirement.h" diff --git a/src/ThemeBuilder/components/properties/PointPropertyEditor.cpp b/src/ThemeBuilder/components/properties/PointPropertyEditor.cpp index 6d4277aa..d8487209 100644 --- a/src/ThemeBuilder/components/properties/PointPropertyEditor.cpp +++ b/src/ThemeBuilder/components/properties/PointPropertyEditor.cpp @@ -1,5 +1,5 @@ #include "PointPropertyEditor.h" -#include "cru/common/Format.h" +#include "cru/base/Format.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/mapper/PointMapper.h" diff --git a/src/ThemeBuilder/components/stylers/BorderStylerEditor.cpp b/src/ThemeBuilder/components/stylers/BorderStylerEditor.cpp index 81eb66d3..1329a08a 100644 --- a/src/ThemeBuilder/components/stylers/BorderStylerEditor.cpp +++ b/src/ThemeBuilder/components/stylers/BorderStylerEditor.cpp @@ -1,5 +1,5 @@ #include "BorderStylerEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/platform/graphics/Brush.h" #include "cru/platform/graphics/Factory.h" #include "cru/platform/gui/UiApplication.h" diff --git a/src/ThemeBuilder/components/stylers/BorderStylerEditor.h b/src/ThemeBuilder/components/stylers/BorderStylerEditor.h index 539262d6..c9435ee9 100644 --- a/src/ThemeBuilder/components/stylers/BorderStylerEditor.h +++ b/src/ThemeBuilder/components/stylers/BorderStylerEditor.h @@ -4,7 +4,7 @@ #include "../properties/OptionalPropertyEditor.h" #include "../properties/ThicknessPropertyEditor.h" #include "StylerEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" namespace cru::theme_builder::components::stylers { class BorderStylerEditor : public StylerEditor { diff --git a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp index 6b8a5033..c8b2a871 100644 --- a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp +++ b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp @@ -6,7 +6,7 @@ #include "MarginStylerEditor.h" #include "PaddingStylerEditor.h" #include "PreferredSizeStylerEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/ThemeManager.h" #include "cru/ui/style/Styler.h" diff --git a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.h b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.h index 57150e83..91d2bff5 100644 --- a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.h +++ b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.h @@ -1,6 +1,6 @@ #pragma once #include "StylerEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/DeleteLater.h" #include "cru/ui/components/PopupButton.h" #include "cru/ui/controls/FlexLayout.h" diff --git a/src/ThemeBuilder/components/stylers/ContentBrushStylerEditor.h b/src/ThemeBuilder/components/stylers/ContentBrushStylerEditor.h index 8385b7c3..ec51c041 100644 --- a/src/ThemeBuilder/components/stylers/ContentBrushStylerEditor.h +++ b/src/ThemeBuilder/components/stylers/ContentBrushStylerEditor.h @@ -2,7 +2,7 @@ #include "../Editor.h" #include "../properties/ColorPropertyEditor.h" #include "StylerEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Styler.h" namespace cru::theme_builder::components::stylers { diff --git a/src/ThemeBuilder/components/stylers/FontStylerEditor.h b/src/ThemeBuilder/components/stylers/FontStylerEditor.h index ccd12113..847b0e2a 100644 --- a/src/ThemeBuilder/components/stylers/FontStylerEditor.h +++ b/src/ThemeBuilder/components/stylers/FontStylerEditor.h @@ -2,7 +2,7 @@ #include "../Editor.h" #include "../properties/FontPropertyEditor.h" #include "StylerEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Styler.h" namespace cru::theme_builder::components::stylers { diff --git a/src/ThemeBuilder/components/stylers/MarginStylerEditor.h b/src/ThemeBuilder/components/stylers/MarginStylerEditor.h index 9de6f1a2..9a1ca750 100644 --- a/src/ThemeBuilder/components/stylers/MarginStylerEditor.h +++ b/src/ThemeBuilder/components/stylers/MarginStylerEditor.h @@ -1,7 +1,7 @@ #pragma once #include "../properties/ThicknessPropertyEditor.h" #include "StylerEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Styler.h" namespace cru::theme_builder::components::stylers { diff --git a/src/ThemeBuilder/components/stylers/PaddingStylerEditor.h b/src/ThemeBuilder/components/stylers/PaddingStylerEditor.h index b78d310b..69565cad 100644 --- a/src/ThemeBuilder/components/stylers/PaddingStylerEditor.h +++ b/src/ThemeBuilder/components/stylers/PaddingStylerEditor.h @@ -1,7 +1,7 @@ #pragma once #include "../properties/ThicknessPropertyEditor.h" #include "StylerEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Styler.h" namespace cru::theme_builder::components::stylers { diff --git a/src/ThemeBuilder/components/stylers/PreferredSizeStylerEditor.h b/src/ThemeBuilder/components/stylers/PreferredSizeStylerEditor.h index 4a64da10..36fdc3d6 100644 --- a/src/ThemeBuilder/components/stylers/PreferredSizeStylerEditor.h +++ b/src/ThemeBuilder/components/stylers/PreferredSizeStylerEditor.h @@ -1,7 +1,7 @@ #pragma once #include "../properties/MeasureLengthPropertyEditor.h" #include "StylerEditor.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Styler.h" namespace cru::theme_builder::components::stylers { diff --git a/src/ThemeBuilder/main.cpp b/src/ThemeBuilder/main.cpp index 0c5b2159..4f4ffe4a 100644 --- a/src/ThemeBuilder/main.cpp +++ b/src/ThemeBuilder/main.cpp @@ -1,5 +1,5 @@ #include "components/MainWindow.h" -#include "cru/common/io/Resource.h" +#include "cru/base/io/Resource.h" #include "cru/platform/bootstrap/Bootstrap.h" #include "cru/ui/ThemeManager.h" #include "cru/ui/ThemeResourceDictionary.h" diff --git a/src/base/Base.cpp b/src/base/Base.cpp new file mode 100644 index 00000000..1704f8a9 --- /dev/null +++ b/src/base/Base.cpp @@ -0,0 +1,7 @@ +#include "cru/base/Base.h" + +#include + +namespace cru { +void UnreachableCode() { std::terminate(); } +} // namespace cru diff --git a/src/base/Buffer.cpp b/src/base/Buffer.cpp new file mode 100644 index 00000000..1213364a --- /dev/null +++ b/src/base/Buffer.cpp @@ -0,0 +1,277 @@ +#include "cru/base/Buffer.h" +#include "cru/base/Exception.h" + +#include + +namespace cru { +namespace { +void CheckSize(Index size) { + if (size < 0) { + throw Exception(u"Size of buffer can't be smaller than 0."); + } +} +} // namespace + +Buffer::Buffer() { + ptr_ = nullptr; + size_ = used_begin_ = used_end_ = 0; +} + +Buffer::Buffer(Index size) { + CheckSize(size); + if (size == 0) { + ptr_ = nullptr; + size_ = used_begin_ = used_end_ = 0; + } else { + ptr_ = new std::byte[size]; + size_ = size; + used_begin_ = used_end_ = 0; + } + AssertValid(); +} + +Buffer::Buffer(const Buffer& other) { Copy_(other); } + +Buffer::Buffer(Buffer&& other) noexcept { Move_(std::move(other)); } + +Buffer& Buffer::operator=(const Buffer& other) { + if (this != &other) { + Delete_(); + Copy_(other); + } + return *this; +} + +Buffer& Buffer::operator=(Buffer&& other) noexcept { + if (this != &other) { + Delete_(); + Move_(std::move(other)); + } + return *this; +} + +Buffer::~Buffer() { Delete_(); } + +void Buffer::AssignBytes(Index dst_offset, std::byte* src, Index src_offset, + Index src_size, bool use_memmove) { + CheckSize(src_size); + + AssertValid(); + + (use_memmove ? std::memmove : std::memcpy)(ptr_ + dst_offset, + src + src_offset, src_size); + AssertValid(); +} + +void Buffer::ResizeBuffer(Index new_size, bool preserve_used) { + CheckSize(new_size); + + AssertValid(); + + if (new_size == 0) { + Delete_(); + ptr_ = nullptr; + size_ = used_begin_ = used_end_ = 0; + return; + } + + auto old_ptr = ptr_; + + ptr_ = new std::byte[new_size]; + size_ = new_size; + used_begin_ = std::min(new_size, used_begin_); + used_end_ = std::min(new_size, used_end_); + + if (old_ptr) { + if (preserve_used && used_begin_ < used_end_) { + std::memcpy(ptr_ + used_begin_, old_ptr + used_begin_, + used_end_ - used_begin_); + } + delete[] old_ptr; + } + + AssertValid(); +} + +Index Buffer::PushFront(const std::byte* other, Index other_size, + bool use_memmove) { + CheckSize(other_size); + + AssertValid(); + + auto copy_size = std::min(used_begin_, other_size); + + if (copy_size) { + used_begin_ -= copy_size; + (use_memmove ? std::memmove : std::memcpy)(ptr_ + used_begin_, other, + copy_size); + } + + AssertValid(); + + return copy_size; +} + +bool Buffer::PushBack(std::byte b) { + AssertValid(); + if (IsUsedReachEnd()) { + return false; + } + ptr_[used_end_] = b; + used_end_++; + AssertValid(); + return true; +} + +Index Buffer::PushBack(const std::byte* other, Index other_size, + bool use_memmove) { + CheckSize(other_size); + + AssertValid(); + + auto copy_size = std::min(size_ - used_end_, other_size); + + if (copy_size) { + (use_memmove ? std::memmove : std::memcpy)(ptr_ + used_end_, other, + copy_size); + used_end_ += copy_size; + } + + AssertValid(); + + return copy_size; +} + +void Buffer::PushBackCount(Index count) { + if (count < 0 || count > GetBackFree()) { + throw Exception(u"Count out of range in PushBackCount."); + } + used_end_ += count; +} + +Index Buffer::PopFront(Index size) { + CheckSize(size); + + AssertValid(); + + auto move = std::min(used_begin_, size); + used_begin_ -= move; + + AssertValid(); + + return move; +} + +Index Buffer::PopFront(std::byte* buffer, Index size, bool use_memmove) { + CheckSize(size); + + AssertValid(); + + auto pop_size = std::min(GetUsedSize(), size); + + if (pop_size) { + used_begin_ += pop_size; + (use_memmove ? std::memmove : std::memcpy)( + buffer, GetUsedBeginPtr() - pop_size, pop_size); + } + + AssertValid(); + + return pop_size; +} + +Index Buffer::PopEnd(Index size) { + CheckSize(size); + + AssertValid(); + + auto move = std::min(size_ - used_end_, size); + used_end_ += move; + + AssertValid(); + + return move; +} + +Index Buffer::PopEnd(std::byte* buffer, Index size, bool use_memmove) { + CheckSize(size); + + AssertValid(); + + auto pop_size = std::min(GetUsedSize(), size); + + if (pop_size) { + used_end_ -= pop_size; + (use_memmove ? std::memmove : std::memcpy)(buffer, GetUsedEndPtr(), + pop_size); + } + + AssertValid(); + + return pop_size; +} + +std::byte* Buffer::Detach(Index* size) { + AssertValid(); + + auto ptr = this->ptr_; + if (size) { + *size = this->size_; + } + this->ptr_ = nullptr; + this->size_ = this->used_begin_ = this->used_end_ = 0; + + AssertValid(); + + return ptr; +} + +void Buffer::Copy_(const Buffer& other) { + if (other.ptr_ == nullptr) { + ptr_ = nullptr; + size_ = used_begin_ = used_end_ = 0; + } else { + ptr_ = new std::byte[other.size_]; + size_ = other.size_; + used_begin_ = other.used_begin_; + used_end_ = other.used_end_; + std::memcpy(ptr_ + used_begin_, other.ptr_ + used_begin_, + used_end_ - used_begin_); + } + AssertValid(); +} + +void Buffer::Move_(Buffer&& other) noexcept { + ptr_ = other.ptr_; + size_ = other.size_; + used_begin_ = other.used_begin_; + used_end_ = other.used_end_; + other.ptr_ = nullptr; + other.size_ = other.used_begin_ = other.used_end_ = 0; + AssertValid(); +} + +void Buffer::Delete_() noexcept { + if (ptr_) { + delete[] ptr_; + } +} + +void Buffer::AssertValid() { + assert(size_ >= 0); + assert(used_begin_ >= 0); + assert(used_begin_ <= size_); + assert(used_end_ >= 0); + assert(used_end_ <= size_); + assert(used_end_ >= used_begin_); + assert((ptr_ == nullptr && size_ == 0) || (ptr_ != nullptr && size_ > 0)); +} + +void swap(Buffer& left, Buffer& right) noexcept { + using std::swap; + swap(left.ptr_, right.ptr_); + swap(left.size_, right.size_); + swap(left.used_begin_, right.used_begin_); + swap(left.used_end_, right.used_end_); +} +} // namespace cru diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt new file mode 100644 index 00000000..19feddba --- /dev/null +++ b/src/base/CMakeLists.txt @@ -0,0 +1,80 @@ +add_library(CruBase + Base.cpp + Buffer.cpp + Exception.cpp + Format.cpp + PropertyTree.cpp + String.cpp + StringToNumberConverter.cpp + StringUtil.cpp + SubProcess.cpp + io/AutoReadStream.cpp + io/BufferStream.cpp + io/CFileStream.cpp + io/Stream.cpp + io/ProxyStream.cpp + io/Resource.cpp + io/MemoryStream.cpp + log/Logger.cpp + log/StdioLogTarget.cpp + platform/Exception.cpp +) +target_compile_definitions(CruBase PRIVATE CRU_BASE_EXPORT_API) +target_include_directories(CruBase PUBLIC ${CRU_INCLUDE_DIR}) +target_compile_definitions(CruBase PUBLIC $<$:CRU_DEBUG>) + +if (UNIX AND NOT EMSCRIPTEN) + target_sources(CruBase PRIVATE + platform/unix/PosixSpawnSubProcess.cpp + platform/unix/UnixFileStream.cpp + platform/unix/UnixPipe.cpp + ) + + if (NOT APPLE) + target_link_libraries(CruBase PUBLIC pthread) + endif() +endif() + +if (APPLE) + find_library(CORE_FOUNDATION CoreFoundation REQUIRED) + target_link_libraries(CruBase PUBLIC ${CORE_FOUNDATION}) + + target_sources(CruBase PRIVATE + platform/osx/Convert.cpp + platform/osx/Exception.cpp + ) +endif() + +if (EMSCRIPTEN) + target_compile_options(CruBase PUBLIC "-fwasm-exceptions") + target_link_options(CruBase PUBLIC "-fwasm-exceptions") + + target_sources(CruBase PRIVATE + platform/web/WebException.cpp + ) +endif() + +if (WIN32) + target_sources(CruBase PRIVATE + platform/win/BridgeComStream.cpp + platform/win/ComAutoInit.cpp + platform/win/DebugLogTarget.cpp + platform/win/Exception.cpp + platform/win/StreamConvert.cpp + platform/win/Win32FileStream.cpp + ) + + target_link_libraries(CruBase PUBLIC Shlwapi.lib) +endif() + +if (WIN32) + target_compile_definitions(CruBase PUBLIC CRU_PLATFORM_WINDOWS) +elseif(APPLE) + target_compile_definitions(CruBase PUBLIC CRU_PLATFORM_OSX) +elseif(EMSCRIPTEN) + target_compile_definitions(CruBase PUBLIC CRU_PLATFORM_EMSCRIPTEN) +else() + target_compile_definitions(CruBase PUBLIC CRU_PLATFORM_LINUX) +endif() + +target_link_libraries(CruBase PUBLIC double-conversion) diff --git a/src/base/Exception.cpp b/src/base/Exception.cpp new file mode 100644 index 00000000..19938970 --- /dev/null +++ b/src/base/Exception.cpp @@ -0,0 +1,36 @@ +#include "cru/base/Exception.h" + +#include "cru/base/Format.h" + +#include + +namespace cru { +Exception::Exception(String message, std::unique_ptr inner) + : message_(std::move(message)), inner_(std::move(inner)) {} + +Exception::~Exception() {} + +const char* Exception::what() const noexcept { + if (!message_.empty() && utf8_message_.empty()) { + utf8_message_ = message_.ToUtf8(); + } + + return utf8_message_.c_str(); +} + +void Exception::AppendMessage(StringView additional_message) { + message_ += u" "; + message_ += additional_message; +} + +void Exception::AppendMessage(std::optional additional_message) { + if (additional_message) AppendMessage(*additional_message); +} + +ErrnoException::ErrnoException(String message) + : ErrnoException(message, errno) {} + +ErrnoException::ErrnoException(String message, int errno_code) + : Exception(Format(u"{}. Errno is {}.", message, errno_code)), + errno_code_(errno_code) {} +} // namespace cru diff --git a/src/base/Format.cpp b/src/base/Format.cpp new file mode 100644 index 00000000..cba4137f --- /dev/null +++ b/src/base/Format.cpp @@ -0,0 +1,111 @@ +#include "cru/base/Format.h" + +namespace cru { +namespace details { +FormatToken ParsePlaceHolder(String place_holder_string) { + if (place_holder_string.empty()) { + return FormatToken::NonePlaceHolder({}); + } + + if (place_holder_string.StartWith(u":")) { + if (place_holder_string.Find(u':', 1) != -1) { + throw Exception(u"Two ':' inside placeholder."); + } + + return FormatToken::NonePlaceHolder(place_holder_string.substr(1)); + } + if (IsDigit(place_holder_string[0])) { + int position = 0; + int index = 0; + while (index < place_holder_string.size() && + IsDigit(place_holder_string[index])) { + position = position * 10 + place_holder_string[index] - '0'; + index++; + } + + String option; + + if (index != place_holder_string.size()) { + if (place_holder_string[index] != ':') { + throw Exception(u"Invalid placeholder in format."); + } + + option = place_holder_string.substr(index + 1); + } + + return FormatToken::PositionedPlaceHolder(position, std::move(option)); + } + + auto separator_index = place_holder_string.Find(':'); + if (separator_index == -1) { + return FormatToken::NamedPlaceHolder(place_holder_string, {}); + } else { + return FormatToken::NamedPlaceHolder( + place_holder_string.substr(0, separator_index), + place_holder_string.substr(separator_index + 1)); + } +} + +std::vector ParseToFormatTokenList(StringView str) { + std::vector result; + + auto push_char = [&result](char16_t c) { + if (result.empty() || result.back().type == FormatTokenType::PlaceHolder) { + result.push_back(FormatToken::Text()); + } + result.back().data.append(c); + }; + + bool try_to_escape = false; + bool is_in_place_holder = false; + String place_holder_string; + + for (auto c : str) { + if (c == u'{') { + if (try_to_escape) { + push_char(u'{'); + try_to_escape = false; + is_in_place_holder = false; + } else { + if (is_in_place_holder) { + throw Exception(u"Invalid format string: '{' inside placeholder."); + } + + try_to_escape = true; + is_in_place_holder = true; + } + } else if (c == u'}') { + if (is_in_place_holder) { + is_in_place_holder = false; + result.push_back(ParsePlaceHolder(std::move(place_holder_string))); + place_holder_string.clear(); + } else { + push_char(u'}'); + } + try_to_escape = false; + } else { + if (is_in_place_holder) { + place_holder_string.push_back(c); + } else { + push_char(c); + } + try_to_escape = false; + } + } + return result; +} + +void FormatAppendFromFormatTokenList( + String& current, const std::vector& format_token_list, + Index index) { + for (Index i = index; i < static_cast(format_token_list.size()); i++) { + const auto& token = format_token_list[i]; + if (token.type == FormatTokenType::PlaceHolder) { + throw Exception(u"More placeholder than args."); + } else { + current += token.data; + } + } +} +} // namespace details +} // namespace cru diff --git a/src/base/PropertyTree.cpp b/src/base/PropertyTree.cpp new file mode 100644 index 00000000..8303a706 --- /dev/null +++ b/src/base/PropertyTree.cpp @@ -0,0 +1,71 @@ +#include "cru/base/PropertyTree.h" +#include +#include "cru/base/Exception.h" + +namespace cru { +String PropertySubTreeRef::CombineKey(StringView left, StringView right) { + return PropertyTree::CombineKey(left, right); +} + +PropertySubTreeRef::PropertySubTreeRef(PropertyTree* tree, String path) + : tree_(tree), path_(std::move(path)) { + Expects(tree); +} + +PropertySubTreeRef PropertySubTreeRef::GetParent() const { + for (Index i = path_.size() - 1; i >= 0; i--) { + if (path_[i] == '.') { + return PropertySubTreeRef(tree_, path_.substr(0, i)); + } + } + + return PropertySubTreeRef(tree_, {}); +} + +PropertySubTreeRef PropertySubTreeRef::GetChild(const String& key) const { + return PropertySubTreeRef(tree_, CombineKey(path_, key)); +} + +String PropertySubTreeRef::GetValue(const String& key) const { + return tree_->GetValue(CombineKey(path_, key)); +} + +void PropertySubTreeRef::SetValue(const String& key, String value) { + tree_->SetValue(CombineKey(path_, key), std::move(value)); +} + +void PropertySubTreeRef::DeleteValue(const String& key) { + tree_->DeleteValue(CombineKey(path_, key)); +} + +String PropertyTree::CombineKey(StringView left, StringView right) { + return String(left) + String(left.empty() ? u"" : u".") + String(right); +} + +PropertyTree::PropertyTree(std::unordered_map values) + : values_(std::move(values)) {} + +String PropertyTree::GetValue(const String& key) const { + auto it = values_.find(key); + if (it == values_.end()) { + throw Exception(u"Property tree has no value."); + } + return it->second; +} + +void PropertyTree::SetValue(const String& key, String value) { + values_[key] = std::move(value); +} + +void PropertyTree::DeleteValue(const String& key) { + auto it = values_.find(key); + if (it != values_.end()) { + values_.erase(it); + } +} + +PropertySubTreeRef PropertyTree::GetSubTreeRef(const String& path) { + return PropertySubTreeRef(this, path); +} + +} // namespace cru diff --git a/src/base/String.cpp b/src/base/String.cpp new file mode 100644 index 00000000..47b64373 --- /dev/null +++ b/src/base/String.cpp @@ -0,0 +1,672 @@ +#include "cru/base/String.h" + +#include "cru/base/Buffer.h" +#include "cru/base/Exception.h" +#include "cru/base/StringToNumberConverter.h" +#include "cru/base/StringUtil.h" + +#include +#include + +#include +#include +#include +#include +#include + +namespace cru { +template +Index GetStrSize(const C* str) { + Index i = 0; + while (str[i]) { + i++; + } + return i; +} + +String String::FromUtf8(const char* str) { + return FromUtf8(str, GetStrSize(str)); +} + +String String::FromUtf8(const char* str, Index size) { + String result; + Utf8CodePointIterator iter(str, size); + for (auto cp : iter) { + Utf16EncodeCodePointAppend( + cp, + std::bind(&String::push_back, std::ref(result), std::placeholders::_1)); + } + return result; +} + +String String::FromUtf8(const std::byte* str, Index size) { + return String::FromUtf8(reinterpret_cast(str), size); +} + +String String::FromUtf8(const Buffer& buffer) { + return String::FromUtf8(buffer.GetUsedBeginPtr(), buffer.GetUsedSize()); +} + +String String::FromStdPath(const std::filesystem::path& path) { + return String::FromUtf8(path.string()); +} + +char16_t String::kEmptyBuffer[1] = {0}; + +String::String(const_pointer str) : String(str, GetStrSize(str)) {} + +String::String(const_pointer str, Index size) { + this->buffer_ = new value_type[size + 1]; + std::memcpy(this->buffer_, str, size * sizeof(char16_t)); + this->buffer_[size] = 0; + this->size_ = size; + this->capacity_ = size; +} + +String::String(size_type size, value_type ch) : String() { + reserve(size); + for (Index i = 0; i < size; i++) { + append(ch); + } +} + +String::String(std::initializer_list l) + : String(l.begin(), l.size()) {} + +#ifdef CRU_PLATFORM_WINDOWS +String::String(const wchar_t* str) : String(str, GetStrSize(str)) {} +String::String(const wchar_t* str, Index size) + : String(reinterpret_cast(str), size) {} +#endif + +String::String(const String& other) { + if (other.size_ == 0) return; + this->buffer_ = new value_type[other.size_ + 1]; + std::memcpy(this->buffer_, other.buffer_, other.size_ * sizeof(value_type)); + this->buffer_[other.size_] = 0; + this->size_ = other.size_; + this->capacity_ = other.size_; +} + +String::String(String&& other) noexcept { + this->buffer_ = other.buffer_; + this->size_ = other.size_; + this->capacity_ = other.capacity_; + other.buffer_ = kEmptyBuffer; + other.size_ = 0; + other.capacity_ = 0; +} + +String& String::operator=(const String& other) { + if (this != &other) { + if (this->buffer_ != kEmptyBuffer) { + delete[] this->buffer_; + } + + if (other.buffer_ == kEmptyBuffer) { + this->buffer_ = kEmptyBuffer; + this->size_ = 0; + this->capacity_ = 0; + } else { + this->buffer_ = new value_type[other.size_ + 1]; + std::memcpy(this->buffer_, other.buffer_, + other.size_ * sizeof(value_type)); + this->buffer_[other.size_] = 0; + this->size_ = other.size_; + this->capacity_ = other.size_; + } + } + return *this; +} + +String& String::operator=(String&& other) noexcept { + if (this != &other) { + if (this->buffer_ != kEmptyBuffer) { + delete[] this->buffer_; + } + + this->buffer_ = other.buffer_; + this->size_ = other.size_; + this->capacity_ = other.capacity_; + other.buffer_ = kEmptyBuffer; + other.size_ = 0; + other.capacity_ = 0; + } + return *this; +} + +String::~String() { + if (this->buffer_ != kEmptyBuffer) { + delete[] this->buffer_; + } +} + +String::String(from_buffer_tag, pointer buffer, Index size, Index capacity) + : buffer_(buffer), size_(size), capacity_(capacity) {} + +void String::clear() { resize(0); } + +void String::resize(Index new_size) { + Expects(new_size >= 0); + + if (new_size == size_) return; + + if (new_size < size_) { + size_ = new_size; + buffer_[size_] = 0; + } else { + reserve(new_size); + std::memset(buffer_ + size_, 0, sizeof(value_type) * (new_size - size_)); + buffer_[new_size] = 0; + size_ = new_size; + } +} + +void String::shrink_to_fit() { + if (capacity_ == size_) return; + if (size_ == 0) { + delete[] buffer_; + buffer_ = kEmptyBuffer; + size_ = 0; + capacity_ = 0; + } else { + auto new_buffer = new value_type[size_ + 1]; + std::memcpy(new_buffer, buffer_, sizeof(value_type) * size_); + delete[] buffer_; + buffer_ = new_buffer; + capacity_ = size_; + } +} + +void String::reserve(Index new_capacity) { + Expects(new_capacity >= 0); + if (new_capacity <= this->capacity_) return; + if (new_capacity > 0) { + pointer new_buffer = new value_type[new_capacity + 1]; + if (this->buffer_ != kEmptyBuffer) { + memcpy(new_buffer, this->buffer_, this->size_ * sizeof(value_type)); + delete[] this->buffer_; + } + new_buffer[this->size_] = 0; + this->buffer_ = new_buffer; + this->capacity_ = new_capacity; + } +} + +String::iterator String::insert(const_iterator pos, const_iterator str, + Index size) { + Expects(pos >= cbegin() && pos <= cend()); + + std::vector backup_buffer; + if (str >= buffer_ && str < buffer_ + size_) { + backup_buffer.resize(size); + std::copy(str, str + size, backup_buffer.begin()); + str = backup_buffer.data(); + } + + Index index = pos - cbegin(); + + Index new_size = size_ + size; + if (new_size > capacity_) { + auto new_capacity = capacity_; + if (new_capacity == 0) { + new_capacity = new_size; + } else { + while (new_capacity < new_size) { + new_capacity *= 2; + } + } + + this->reserve(new_capacity); + } + + std::memmove(begin() + index + size, begin() + index, + (size_ - index) * sizeof(value_type)); + std::memcpy(begin() + index, str, size * sizeof(value_type)); + + buffer_[new_size] = 0; + size_ = new_size; + + return begin() + new_size; +} + +String::iterator String::erase(const_iterator start, const_iterator end) { + Expects(buffer_ <= start && start <= end && end <= buffer_ + size_); + + Index new_size = size_ - (end - start); + + auto s = const_cast(start); + auto e = const_cast(end); + + std::memmove(s, e, (cend() - end) * sizeof(value_type)); + this->size_ = new_size; + this->buffer_[new_size] = 0; + + return s; +} + +String& String::operator+=(StringView other) { + append(other); + return *this; +} + +StringView String::View() const { return *this; } + +Index String::Find(value_type value, Index start) const { + return View().Find(value, start); +} + +std::vector String::Split(value_type separator, + bool remove_space_line) const { + return View().Split(separator, remove_space_line); +} + +std::vector String::SplitToLines(bool remove_space_line) const { + return View().SplitToLines(remove_space_line); +} + +bool String::StartWith(StringView str) const { return View().StartWith(str); } + +bool String::EndWith(StringView str) const { return View().EndWith(str); } + +std::string String::ToUtf8() const { return View().ToUtf8(); } + +Buffer String::ToUtf8Buffer(bool end_zero) const { + return View().ToUtf8Buffer(); +} + +String& String::TrimStart() { + if (size_ == 0) return *this; + + auto start = begin(); + while (start != end() && IsWhitespace(*start)) { + ++start; + } + + if (start == end()) { + clear(); + } else { + erase(begin(), start); + } + + return *this; +} + +String& String::TrimEnd() { + if (size_ == 0) return *this; + while (size_ > 0 && IsWhitespace(buffer_[size_ - 1])) { + size_--; + } + + return *this; +} + +String& String::Trim() { + TrimStart(); + TrimEnd(); + return *this; +} + +void String::AppendCodePoint(CodePoint code_point) { + if (!Utf16EncodeCodePointAppend( + code_point, + std::bind(&String::push_back, this, std::placeholders::_1))) { + throw TextEncodeException(u"Code point out of range."); + } +} + +Index String::IndexFromCodeUnitToCodePoint(Index code_unit_index) const { + return View().IndexFromCodeUnitToCodePoint(code_unit_index); +} + +Index String::IndexFromCodePointToCodeUnit(Index code_point_index) const { + return View().IndexFromCodePointToCodeUnit(code_point_index); +} + +Range String::RangeFromCodeUnitToCodePoint(Range code_unit_range) const { + return View().RangeFromCodeUnitToCodePoint(code_unit_range); +} + +Range String::RangeFromCodePointToCodeUnit(Range code_point_range) const { + return View().RangeFromCodePointToCodeUnit(code_point_range); +} + +int String::ParseToInt(Index* processed_characters_count, + StringToNumberFlag flags, int base) const { + return View().ParseToInt(processed_characters_count, flags, base); +} + +long long String::ParseToLongLong(Index* processed_characters_count, + StringToNumberFlag flags, int base) const { + return View().ParseToLongLong(processed_characters_count, flags, base); +} + +float String::ParseToFloat(Index* processed_characters_count, + StringToNumberFlag flags) const { + return View().ParseToFloat(processed_characters_count, flags); +} + +double String::ParseToDouble(Index* processed_characters_count, + StringToNumberFlag flags) const { + return View().ParseToDouble(processed_characters_count, flags); +} + +std::vector String::ParseToFloatList(value_type separator) const { + return View().ParseToFloatList(separator); +} + +std::vector String::ParseToDoubleList(value_type separator) const { + return View().ParseToDoubleList(separator); +} + +std::ostream& operator<<(std::ostream& os, const String& value) { + os << value.ToUtf8(); + return os; +} + +namespace { +inline int Compare(char16_t left, char16_t right) { + if (left < right) return -1; + if (left > right) return 1; + return 0; +} + +inline int CaseInsensitiveCompare(char16_t left, char16_t right) { + return Compare(ToLower(left), ToLower(right)); +} +} // namespace + +int String::Compare(const String& other) const { return View().Compare(other); } +int String::CaseInsensitiveCompare(const String& other) const { + return View().CaseInsensitiveCompare(other); +} + +int StringView::Compare(const StringView& other) const { + const_iterator i1 = cbegin(); + const_iterator i2 = other.cbegin(); + + const_iterator end1 = cend(); + const_iterator end2 = other.cend(); + + while (i1 != end1 && i2 != end2) { + int r = cru::Compare(*i1, *i2); + if (r != 0) return r; + i1++; + i2++; + } + + if (i1 == end1) { + if (i2 == end2) { + return 0; + } else { + return -1; + } + } else { + return 1; + } +} + +int StringView::CaseInsensitiveCompare(const StringView& other) const { + const_iterator i1 = cbegin(); + const_iterator i2 = other.cbegin(); + + const_iterator end1 = cend(); + const_iterator end2 = other.cend(); + + while (i1 != end1 && i2 != end2) { + int r = cru::CaseInsensitiveCompare(*i1, *i2); + if (r != 0) return r; + i1++; + i2++; + } + + if (i1 == end1) { + if (i2 == end2) { + return 0; + } else { + return -1; + } + } else { + return 1; + } +} + +StringView StringView::substr(Index pos) { + Expects(pos >= 0 && pos < size_); + return StringView(ptr_ + pos, size_ - pos); +} + +StringView StringView::substr(Index pos, Index size) { + Expects(pos >= 0 && pos < size_); + + return StringView(ptr_ + pos, std::min(size, size_ - pos)); +} + +Index StringView::Find(value_type value, Index start) const { + Expects(start >= 0 && start <= size_); + + for (Index i = start; i < size_; ++i) { + if (ptr_[i] == value) return i; + } + return -1; +} + +std::vector StringView::Split(value_type separator, + bool remove_space_line) const { + std::vector result; + + if (size_ == 0) return result; + + Index line_start = 0; + Index line_end = 0; + while (line_end < size_) { + if (ptr_[line_end] == separator) { + if (remove_space_line) { + bool add = false; + for (Index i = line_start; i < line_end; i++) { + if (!IsWhitespace(ptr_[i])) { + add = true; + break; + } + } + if (add) result.emplace_back(begin() + line_start, begin() + line_end); + } else { + result.emplace_back(begin() + line_start, begin() + line_end); + } + line_start = line_end + 1; + line_end = line_start; + } else { + line_end++; + } + } + + if (remove_space_line) { + bool add = false; + for (Index i = line_start; i < size_; i++) { + if (!IsWhitespace(ptr_[i])) { + add = true; + break; + } + } + if (add) result.emplace_back(begin() + line_start, begin() + size_); + } else { + result.emplace_back(begin() + line_start, begin() + size_); + } + + return result; +} + +std::vector StringView::SplitToLines(bool remove_space_line) const { + return Split(u'\n', remove_space_line); +} + +bool StringView::StartWith(StringView str) const { + if (str.size() > size_) return false; + return std::memcmp(str.data(), ptr_, str.size()) == 0; +} + +bool StringView::EndWith(StringView str) const { + if (str.size() > size_) return false; + return std::memcmp(str.data(), ptr_ + size_ - str.size(), str.size()) == 0; +} + +Index StringView::IndexFromCodeUnitToCodePoint(Index code_unit_index) const { + auto iter = CodePointIterator(); + Index result = 0; + while (iter.GetPosition() < code_unit_index && !iter.IsPastEnd()) { + ++iter; + ++result; + } + return result; +} + +Index StringView::IndexFromCodePointToCodeUnit(Index code_point_index) const { + auto iter = CodePointIterator(); + Index cpi = 0; + while (cpi < code_point_index && !iter.IsPastEnd()) { + ++iter; + ++cpi; + } + return iter.GetPosition(); +} + +Range StringView::RangeFromCodeUnitToCodePoint(Range code_unit_range) const { + return Range::FromTwoSides( + IndexFromCodeUnitToCodePoint(code_unit_range.GetStart()), + IndexFromCodeUnitToCodePoint(code_unit_range.GetEnd())); +} + +Range StringView::RangeFromCodePointToCodeUnit(Range code_point_range) const { + return Range::FromTwoSides( + IndexFromCodePointToCodeUnit(code_point_range.GetStart()), + IndexFromCodePointToCodeUnit(code_point_range.GetEnd())); +} + +std::string StringView::ToUtf8() const { + std::string result; + for (auto cp : CodePointIterator()) { + Utf8EncodeCodePointAppend( + cp, std::bind(&std::string::push_back, std::ref(result), + std::placeholders::_1)); + } + return result; +} + +Buffer StringView::ToUtf8Buffer(bool end_zero) const { + const Index grow_step = 10; + Buffer buffer(grow_step); // Maybe another init value is more reasonable. + auto push_back = [&buffer](char c) { + if (buffer.IsUsedReachEnd()) { + buffer.ResizeBuffer(buffer.GetBufferSize() + grow_step, true); + } + buffer.PushBack(static_cast(c)); + }; + for (auto cp : CodePointIterator()) { + Utf8EncodeCodePointAppend(cp, push_back); + } + if (end_zero) { + push_back(0); + } + return buffer; +} + +int StringView::ParseToInt(Index* processed_characters_count, + StringToNumberFlag flags, int base) const { + return ParseToInteger(processed_characters_count, flags, base); +} + +long long StringView::ParseToLongLong(Index* processed_characters_count, + StringToNumberFlag flags, + int base) const { + return ParseToInteger(processed_characters_count, flags, base); +} + +static int MapStringToDoubleFlags(StringToNumberFlag flags) { + int f = double_conversion::StringToDoubleConverter::ALLOW_CASE_INSENSIBILITY; + if (flags & StringToNumberFlags::kAllowLeadingSpaces) { + f |= double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES; + } + if (flags & StringToNumberFlags::kAllowTrailingSpaces) { + f |= double_conversion::StringToDoubleConverter::ALLOW_TRAILING_SPACES; + } + if (flags & StringToNumberFlags::kAllowTrailingJunk) { + f |= double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK; + } + return f; +} + +static double_conversion::StringToDoubleConverter CreateStringToDoubleConverter( + StringToNumberFlag flags) { + return {MapStringToDoubleFlags(flags), 0.0, NAN, "inf", "nan"}; +} + +float StringView::ParseToFloat(Index* processed_characters_count, + StringToNumberFlag flags) const { + int pcc; + auto result = CreateStringToDoubleConverter(flags).StringToFloat( + reinterpret_cast(ptr_), static_cast(size_), &pcc); + if (processed_characters_count != nullptr) { + *processed_characters_count = pcc; + } + + if (flags & StringToNumberFlags::kThrowOnError && std::isnan(result)) { + throw Exception(u"Result of string to float conversion is NaN"); + } + + return result; +} + +double StringView::ParseToDouble(Index* processed_characters_count, + StringToNumberFlag flags) const { + int pcc; + auto result = CreateStringToDoubleConverter(flags).StringToDouble( + reinterpret_cast(ptr_), static_cast(size_), &pcc); + if (processed_characters_count != nullptr) { + *processed_characters_count = pcc; + } + + if (flags & StringToNumberFlags::kThrowOnError && std::isnan(result)) { + throw Exception(u"Result of string to double conversion is NaN"); + } + + return result; +} + +std::vector StringView::ParseToFloatList(value_type separator) const { + std::vector result; + auto list = Split(separator, true); + for (auto& item : list) { + auto value = item.ParseToFloat(); + if (std::isnan(value)) { + throw Exception(u"Invalid double value."); + } + result.push_back(value); + } + return result; +} + +std::vector StringView::ParseToDoubleList(value_type separator) const { + std::vector result; + auto list = Split(separator, true); + for (auto& item : list) { + auto value = item.ParseToDouble(); + if (std::isnan(value)) { + throw Exception(u"Invalid double value."); + } + result.push_back(value); + } + return result; +} + +String ToLower(StringView s) { + String result; + for (auto c : s) result.push_back(ToLower(c)); + return result; +} + +String ToUpper(StringView s) { + String result; + for (auto c : s) result.push_back(ToUpper(c)); + return result; +} +} // namespace cru diff --git a/src/base/StringToNumberConverter.cpp b/src/base/StringToNumberConverter.cpp new file mode 100644 index 00000000..65aec48e --- /dev/null +++ b/src/base/StringToNumberConverter.cpp @@ -0,0 +1,170 @@ +#include "cru/base/StringToNumberConverter.h" +#include "cru/base/Exception.h" + +namespace cru { +bool StringToIntegerConverter::CheckParams() const { + return base == 0 || base >= 2 & base <= 36; +} + +static bool IsSpace(char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; +} + +StringToIntegerResult StringToIntegerConverter::Parse( + const char* const str, const Index size, + Index* processed_characters_count) const { + if (str == nullptr) throw std::invalid_argument("Invalid str."); + if (size < 0) throw std::invalid_argument("Invalid size."); + if (!CheckParams()) throw std::invalid_argument("Invalid parsing flags."); + + const bool throw_on_error = flags.Has(StringToNumberFlags::kThrowOnError); + + auto const end = str + size; + + auto current = str; + + if (flags & StringToNumberFlags::kAllowLeadingSpaces) { + while (current != end && IsSpace(*current)) { + current++; + } + } + + if (current == end) { + if (processed_characters_count) { + *processed_characters_count = 0; + } + if (throw_on_error) { + throw Exception(u"Empty string (after reading leading spaces)."); + } else { + return {false, 0}; + } + } + + bool negate = false; + + if (*current == '-') { + ++current; + negate = true; + } else if (*current == '+') { + ++current; + } + + if (current == end) { + if (processed_characters_count) { + *processed_characters_count = 0; + } + if (throw_on_error) { + throw Exception(u"Empty string (after reading sign)."); + } else { + return {false, 0}; + } + } + + int real_base = base; + + if (real_base == 0) { + if (*current == '0') { + ++current; + if (current == end) { + if (processed_characters_count) { + *processed_characters_count = current - str; + } + return {negate, 0}; + } else if (*current == 'x' || *current == 'X') { + ++current; + real_base = 16; + } else if (*current == 'b' || *current == 'B') { + ++current; + real_base = 2; + } else { + real_base = 8; + } + } else { + real_base = 10; + } + } + + if (current == end) { + if (processed_characters_count) { + *processed_characters_count = 0; + } + if (throw_on_error) { + throw Exception(u"Empty string (after reading head base indicator)."); + } else { + return {false, 0}; + } + } + + const bool allow_leading_zero = + flags.Has(StringToNumberFlags::kAllowLeadingZeroForInteger); + + while (current != end && *current == '0') { + current++; + } + + if (current == end) { + if (processed_characters_count) { + *processed_characters_count = current - str; + } + return {negate, 0}; + } + + const bool allow_trailing_junk = + flags.Has(StringToNumberFlags::kAllowTrailingJunk); + const bool allow_trailing_spaces = + flags.Has(StringToNumberFlags::kAllowTrailingSpaces); + + unsigned long long result = 0; + + while (current != end) { + const char c = *current; + if (c >= '0' && c <= (real_base > 10 ? '9' : real_base + '0' - 1)) { + result = result * real_base + c - '0'; + current++; + } else if (real_base > 10 && c >= 'a' && c <= (real_base + 'a' - 10 - 1)) { + result = result * real_base + c - 'a' + 10; + current++; + } else if (real_base > 10 && c >= 'A' && c <= (real_base + 'A' - 10 - 1)) { + result = result * real_base + c - 'A' + 10; + current++; + } else if (allow_trailing_junk) { + break; + } else if (allow_trailing_spaces && IsSpace(c)) { + break; + } else { + if (processed_characters_count) { + *processed_characters_count = 0; + } + if (throw_on_error) { + throw Exception(String(u"Read invalid character '") + c + u"'."); + } else { + return {false, 0}; + } + } + } + + if (allow_trailing_spaces) { + while (current != end && IsSpace(*current)) { + current++; + } + + if (current != end) { + if (processed_characters_count) { + *processed_characters_count = 0; + } + if (throw_on_error) { + throw Exception(u"There is trailing junk."); + } else { + return {false, 0}; + } + } + } + + if (processed_characters_count) { + *processed_characters_count = current - str; + } + + return {negate, result}; +} + +} // namespace cru diff --git a/src/base/StringUtil.cpp b/src/base/StringUtil.cpp new file mode 100644 index 00000000..9053f384 --- /dev/null +++ b/src/base/StringUtil.cpp @@ -0,0 +1,243 @@ +#include "cru/base/StringUtil.h" +#include "cru/base/Base.h" +#include "cru/base/Exception.h" + +namespace cru { +using details::ExtractBits; + +CodePoint Utf8NextCodePoint(const char* ptr, Index size, Index current, + Index* next_position) { + CodePoint result; + + if (current >= size) { + result = k_invalid_code_point; + } else { + const auto cu0 = static_cast(ptr[current++]); + + auto read_next_folowing_code = [ptr, size, ¤t]() -> CodePoint { + if (current == size) + throw TextEncodeException( + u"Unexpected end when read continuing byte of multi-byte code " + "point."); + + const auto u = static_cast(ptr[current]); + if (!(u & (1u << 7)) || (u & (1u << 6))) { + throw TextEncodeException( + u"Unexpected bad-format (not 0b10xxxxxx) continuing byte of " + "multi-byte code point."); + } + + return ExtractBits(ptr[current++]); + }; + + if ((1u << 7) & cu0) { + if ((1u << 6) & cu0) { // 2~4-length code point + if ((1u << 5) & cu0) { // 3~4-length code point + if ((1u << 4) & cu0) { // 4-length code point + if (cu0 & (1u << 3)) { + throw TextEncodeException( + u"Unexpected bad-format begin byte (not 0b11110xxx) of 4-byte" + "code point."); + } + + const CodePoint s0 = ExtractBits(cu0) + << (6 * 3); + const CodePoint s1 = read_next_folowing_code() << (6 * 2); + const CodePoint s2 = read_next_folowing_code() << 6; + const CodePoint s3 = read_next_folowing_code(); + result = s0 + s1 + s2 + s3; + } else { // 3-length code point + const CodePoint s0 = ExtractBits(cu0) + << (6 * 2); + const CodePoint s1 = read_next_folowing_code() << 6; + const CodePoint s2 = read_next_folowing_code(); + result = s0 + s1 + s2; + } + } else { // 2-length code point + const CodePoint s0 = ExtractBits(cu0) + << 6; + const CodePoint s1 = read_next_folowing_code(); + result = s0 + s1; + } + } else { + throw TextEncodeException( + u"Unexpected bad-format (0b10xxxxxx) begin byte of a code point."); + } + } else { + result = static_cast(cu0); + } + } + + if (next_position != nullptr) *next_position = current; + return result; +} + +CodePoint Utf16NextCodePoint(const char16_t* ptr, Index size, Index current, + Index* next_position) { + CodePoint result; + + if (current >= size) { + result = k_invalid_code_point; + } else { + const auto cu0 = ptr[current++]; + + if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point + result = static_cast(cu0); + } else if (IsUtf16SurrogatePairLeading(cu0)) { // 2-length code point + if (current >= size) { + throw TextEncodeException( + u"Unexpected end when reading second code unit of surrogate pair."); + } + const auto cu1 = ptr[current++]; + + if (!IsUtf16SurrogatePairTrailing(cu1)) { + throw TextEncodeException( + u"Unexpected bad-range second code unit of surrogate pair."); + } + + const auto s0 = ExtractBits(cu0) << 10; + const auto s1 = ExtractBits(cu1); + + result = s0 + s1 + 0x10000; + + } else { + throw TextEncodeException( + u"Unexpected bad-range first code unit of surrogate pair."); + } + } + + if (next_position != nullptr) *next_position = current; + return result; +} + +CodePoint Utf16PreviousCodePoint(const char16_t* ptr, Index size, Index current, + Index* previous_position) { + CRU_UNUSED(size) + + CodePoint result; + if (current <= 0) { + result = k_invalid_code_point; + } else { + const auto cu0 = ptr[--current]; + + if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point + result = static_cast(cu0); + } else if (IsUtf16SurrogatePairTrailing(cu0)) { // 2-length code point + if (current <= 0) { + throw TextEncodeException( + u"Unexpected end when reading first code unit of surrogate pair."); + } + const auto cu1 = ptr[--current]; + + if (!IsUtf16SurrogatePairLeading(cu1)) { + throw TextEncodeException( + u"Unexpected bad-range first code unit of surrogate pair."); + } + + const auto s0 = ExtractBits(cu1) << 10; + const auto s1 = ExtractBits(cu0); + + result = s0 + s1 + 0x10000; + + } else { + throw TextEncodeException( + u"Unexpected bad-range second code unit of surrogate pair."); + } + } + + if (previous_position != nullptr) *previous_position = current; + return result; +} + +bool Utf16IsValidInsertPosition(const char16_t* ptr, Index size, + Index position) { + if (position < 0) return false; + if (position > size) return false; + if (position == 0) return true; + if (position == size) return true; + return !IsUtf16SurrogatePairTrailing(ptr[position]); +} + +Index Utf16BackwardUntil(const char16_t* ptr, Index size, Index position, + const std::function& predicate) { + if (position <= 0) return position; + while (true) { + Index p = position; + auto c = Utf16PreviousCodePoint(ptr, size, p, &position); + if (predicate(c)) return p; + if (c == k_invalid_code_point) return p; + } + UnreachableCode(); +} + +Index Utf16ForwardUntil(const char16_t* ptr, Index size, Index position, + const std::function& predicate) { + if (position >= size) return position; + while (true) { + Index p = position; + auto c = Utf16NextCodePoint(ptr, size, p, &position); + if (predicate(c)) return p; + if (c == k_invalid_code_point) return p; + } + UnreachableCode(); +} + +inline bool IsSpace(CodePoint c) { return c == 0x20 || c == 0xA; } + +Index Utf16PreviousWord(const char16_t* ptr, Index size, Index position, + bool* is_space) { + if (position <= 0) return position; + auto c = Utf16PreviousCodePoint(ptr, size, position, nullptr); + if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). + if (is_space) *is_space = true; + return Utf16BackwardUntil(ptr, size, position, + [](CodePoint c) { return !IsSpace(c); }); + } else { + if (is_space) *is_space = false; + return Utf16BackwardUntil(ptr, size, position, IsSpace); + } +} + +Index Utf16NextWord(const char16_t* ptr, Index size, Index position, + bool* is_space) { + if (position >= size) return position; + auto c = Utf16NextCodePoint(ptr, size, position, nullptr); + if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). + if (is_space) *is_space = true; + return Utf16ForwardUntil(ptr, size, position, + [](CodePoint c) { return !IsSpace(c); }); + } else { + if (is_space) *is_space = false; + return Utf16ForwardUntil(ptr, size, position, IsSpace); + } +} + +char16_t ToLower(char16_t c) { + if (c >= u'A' && c <= u'Z') { + return c - u'A' + u'a'; + } + return c; +} + +char16_t ToUpper(char16_t c) { + if (c >= u'a' && c <= u'z') { + return c - u'a' + u'A'; + } + return c; +} + +bool IsWhitespace(char16_t c) { + return c == u' ' || c == u'\t' || c == u'\n' || c == u'\r'; +} + +bool IsDigit(char16_t c) { return c >= u'0' && c <= u'9'; } + +Utf8CodePointIterator CreateUtf8Iterator(const std::byte* buffer, Index size) { + return Utf8CodePointIterator(reinterpret_cast(buffer), size); +} + +Utf8CodePointIterator CreateUtf8Iterator(const std::vector& buffer) { + return CreateUtf8Iterator(buffer.data(), buffer.size()); +} + +} // namespace cru diff --git a/src/base/SubProcess.cpp b/src/base/SubProcess.cpp new file mode 100644 index 00000000..1133b848 --- /dev/null +++ b/src/base/SubProcess.cpp @@ -0,0 +1,209 @@ +#include "cru/base/SubProcess.h" + +#include + +#ifdef CRU_PLATFORM_UNIX +#include "cru/base/platform/unix/PosixSpawnSubProcess.h" +#endif + +namespace cru { + +#ifdef CRU_PLATFORM_UNIX +using ThisPlatformSubProcessImpl = platform::unix::PosixSpawnSubProcessImpl; +#endif + +PlatformSubProcess::PlatformSubProcess( + SubProcessStartInfo start_info, + std::shared_ptr impl) + : state_(new State(std::move(start_info), std::move(impl))), + lock_(state_->mutex, std::defer_lock) {} + +PlatformSubProcess::~PlatformSubProcess() {} + +void PlatformSubProcess::Start() { + std::lock_guard lock_guard(this->lock_); + + if (this->state_->status != SubProcessStatus::Prepare) { + throw SubProcessException(u"The process has already tried to start."); + } + + try { + this->state_->impl->PlatformCreateProcess(this->state_->start_info); + this->state_->status = SubProcessStatus::Running; + + auto thread = std::thread([state = state_] { + std::unique_lock lock(state->mutex); + state->exit_result = state->impl->PlatformWaitForProcess(); + state->status = SubProcessStatus::Exited; + state->condition_variable.notify_all(); + }); + + thread.detach(); + } catch (const std::exception& e) { + this->state_->status = SubProcessStatus::FailedToStart; + throw SubProcessFailedToStartException(u"Sub-process failed to start. " + + String::FromUtf8(e.what())); + } +} + +void PlatformSubProcess::Wait( + std::optional wait_time) { + std::lock_guard lock_guard(this->lock_); + + if (this->state_->status == SubProcessStatus::Prepare) { + throw SubProcessException( + u"The process does not start. Can't wait for it."); + } + + if (this->state_->status == SubProcessStatus::FailedToStart) { + throw SubProcessException( + u"The process failed to start. Can't wait for it."); + } + + if (this->state_->status == SubProcessStatus::Exited) { + return; + } + + auto predicate = [this] { + return this->state_->status == SubProcessStatus::Exited; + }; + + if (wait_time) { + this->state_->condition_variable.wait_for(this->lock_, *wait_time, + predicate); + } else { + this->state_->condition_variable.wait(this->lock_, predicate); + } +} + +void PlatformSubProcess::Kill() { + std::lock_guard lock_guard(this->lock_); + + if (this->state_->status == SubProcessStatus::Prepare) { + throw SubProcessException(u"The process does not start. Can't kill it."); + } + + if (this->state_->status == SubProcessStatus::FailedToStart) { + throw SubProcessException(u"The process failed to start. Can't kill it."); + } + + if (this->state_->status == SubProcessStatus::Exited) { + return; + } + + if (this->state_->killed) { + return; + } + + this->state_->impl->PlatformKillProcess(); + this->state_->killed = true; +} + +SubProcessStatus PlatformSubProcess::GetStatus() { + std::lock_guard lock_guard(this->lock_); + return this->state_->status; +} + +SubProcessExitResult PlatformSubProcess::GetExitResult() { + std::lock_guard lock_guard(this->lock_); + + if (this->state_->status == SubProcessStatus::Prepare) { + throw SubProcessException( + u"The process does not start. Can't get exit result."); + } + + if (this->state_->status == SubProcessStatus::FailedToStart) { + throw SubProcessException( + u"The process failed to start. Can't get exit result."); + } + + if (this->state_->status == SubProcessStatus::Running) { + throw SubProcessException( + u"The process is running. Can't get exit result."); + } + + return this->state_->exit_result; +} + +io::Stream* PlatformSubProcess::GetStdinStream() { + return this->state_->impl->GetStdinStream(); +} + +io::Stream* PlatformSubProcess::GetStdoutStream() { + return this->state_->impl->GetStdoutStream(); +} + +io::Stream* PlatformSubProcess::GetStderrStream() { + return this->state_->impl->GetStderrStream(); +} + +SubProcess SubProcess::Create(String program, std::vector arguments, + std::unordered_map environments) { + SubProcessStartInfo start_info; + start_info.program = std::move(program); + start_info.arguments = std::move(arguments); + start_info.environments = std::move(environments); + return SubProcess(std::move(start_info)); +} + +SubProcessExitResult SubProcess::Call( + String program, std::vector arguments, + std::unordered_map environments) { + auto process = + Create(std::move(program), std::move(arguments), std::move(environments)); + process.Wait(); + return process.GetExitResult(); +} + +SubProcess::SubProcess(SubProcessStartInfo start_info) { + platform_process_.reset(new PlatformSubProcess( + std::move(start_info), std::make_shared())); + platform_process_->Start(); +} + +SubProcess::~SubProcess() {} + +void SubProcess::Wait(std::optional wait_time) { + CheckValid(); + platform_process_->Wait(wait_time); +} + +void SubProcess::Kill() { + CheckValid(); + platform_process_->Kill(); +} + +SubProcessStatus SubProcess::GetStatus() { + CheckValid(); + return platform_process_->GetStatus(); +} + +SubProcessExitResult SubProcess::GetExitResult() { + CheckValid(); + return platform_process_->GetExitResult(); +} + +io::Stream* SubProcess::GetStdinStream() { + CheckValid(); + return platform_process_->GetStdinStream(); +} + +io::Stream* SubProcess::GetStdoutStream() { + CheckValid(); + return platform_process_->GetStdoutStream(); +} + +io::Stream* SubProcess::GetStderrStream() { + CheckValid(); + return platform_process_->GetStderrStream(); +} + +void SubProcess::Detach() { auto p = platform_process_.release(); } + +void SubProcess::CheckValid() const { + if (!IsValid()) { + throw SubProcessException(u"SubProcess instance is invalid."); + } +} + +} // namespace cru diff --git a/src/base/io/AutoReadStream.cpp b/src/base/io/AutoReadStream.cpp new file mode 100644 index 00000000..c24f61d1 --- /dev/null +++ b/src/base/io/AutoReadStream.cpp @@ -0,0 +1,56 @@ +#include "cru/base/io/AutoReadStream.h" +#include "cru/base/io/Stream.h" + +#include + +namespace cru::io { + +AutoReadStream::AutoReadStream(Stream* stream, bool auto_delete, + const AutoReadStreamOptions& options) + : Stream(false, true, stream->CanSeek()) { + auto buffer_stream_options = options.GetBufferStreamOptions(); + stream_ = stream; + size_per_read_ = buffer_stream_options.GetBlockSizeOrDefault(); + buffer_stream_ = std::make_unique(buffer_stream_options); + background_thread_ = std::thread(&AutoReadStream::BackgroundThreadRun, this); +} + +AutoReadStream::~AutoReadStream() { + if (auto_delete_) { + delete stream_; + } +} + +Index AutoReadStream::DoRead(std::byte* buffer, Index offset, Index size) { + std::unique_lock lock(buffer_stream_mutex_); + return buffer_stream_->Read(buffer, offset, size); +} + +Index AutoReadStream::DoWrite(const std::byte* buffer, Index offset, + Index size) { + return stream_->Write(buffer, offset, size); +} + +void AutoReadStream::DoFlush() { stream_->Flush(); } + +void AutoReadStream::DoClose() {} + +void AutoReadStream::BackgroundThreadRun() { + std::vector buffer(size_per_read_); + while (true) { + try { + auto read = stream_->Read(buffer.data(), buffer.size()); + if (read == 0) { + buffer_stream_->SetEof(); + break; + } else { + buffer_stream_->Write(buffer.data(), read); + } + } catch (const StreamAlreadyClosedException& exception) { + buffer_stream_->SetEof(); + break; + } + } +} + +} // namespace cru::io diff --git a/src/base/io/BufferStream.cpp b/src/base/io/BufferStream.cpp new file mode 100644 index 00000000..e81731e8 --- /dev/null +++ b/src/base/io/BufferStream.cpp @@ -0,0 +1,109 @@ +#include "cru/base/io/BufferStream.h" +#include "cru/base/io/Stream.h" + +namespace cru::io { +BufferStream::BufferStream(const BufferStreamOptions& options) + : Stream(false, true, true) { + block_size_ = options.GetBlockSizeOrDefault(); + max_block_count_ = options.GetMaxBlockCount(); + + eof_ = false; +} + +BufferStream::~BufferStream() { DoClose(); } + +Index BufferStream::DoRead(std::byte* buffer, Index offset, Index size) { + std::unique_lock lock(mutex_); + + condition_variable_.wait(lock, + [this] { return !buffer_list_.empty() || eof_; }); + + if (buffer_list_.empty() && eof_) { + return 0; + } + + auto full = max_block_count_ > 0 && buffer_list_.size() == max_block_count_; + + Index read = 0; + + while (!buffer_list_.empty()) { + auto& stream_buffer = buffer_list_.front(); + auto this_read = + stream_buffer.PopFront(buffer + offset + read, size - read); + if (stream_buffer.GetUsedSize() == 0) { + buffer_list_.pop_front(); + } + read += this_read; + if (read == size) { + break; + } + } + + if (full && buffer_list_.size() < max_block_count_) { + // By convention, there should be at most one producer waiting. So + // notify_one and notify_all should be the same. + condition_variable_.notify_one(); + } + + return read; +} + +Index BufferStream::DoWrite(const std::byte* buffer, Index offset, Index size) { + std::unique_lock lock(mutex_); + + if (eof_) { + throw WriteAfterEofException( + u"Stream has been set eof. Can't write to it any more."); + } + + condition_variable_.wait(lock, [this] { + return max_block_count_ <= 0 || buffer_list_.size() < max_block_count_ || + buffer_list_.back().GetBackFree() > 0; + }); + + auto empty = buffer_list_.empty(); + + Index written = 0; + + if (empty) { + buffer_list_.push_back(Buffer(block_size_)); + } + + while (true) { + if (buffer_list_.back().GetBackFree() == 0) { + if (max_block_count_ > 0 && buffer_list_.size() == max_block_count_) { + break; + } + buffer_list_.push_back(Buffer(block_size_)); + } + auto& stream_buffer = buffer_list_.back(); + auto this_written = + stream_buffer.PushBack(buffer + offset + written, size - written); + written += this_written; + if (written == size) { + break; + } + } + + if (empty) { + // By convention, there should be at most one consumer waiting. So + // notify_one and notify_all should be the same. + condition_variable_.notify_one(); + } + + return written; +} + +void BufferStream::SetEof() { + std::unique_lock lock(mutex_); + + eof_ = true; + if (buffer_list_.empty()) { + // By convention, there should be at most one consumer waiting. So + // notify_one and notify_all should be the same. + condition_variable_.notify_one(); + } +} + +void BufferStream::DoClose() { CRU_STREAM_BEGIN_CLOSE } +} // namespace cru::io diff --git a/src/base/io/CFileStream.cpp b/src/base/io/CFileStream.cpp new file mode 100644 index 00000000..d5acc707 --- /dev/null +++ b/src/base/io/CFileStream.cpp @@ -0,0 +1,96 @@ +#include "cru/base/io/CFileStream.h" +#include "cru/base/Exception.h" +#include "cru/base/io/Stream.h" + +#include + +namespace cru::io { +static bool ModeCanRead(const char* mode) { + for (const char* p = mode; *p != '\0'; p++) { + if (*p == 'r' || *p == '+') { + return true; + } + } + return false; +} + +static bool ModeCanWrite(const char* mode) { + for (const char* p = mode; *p != '\0'; p++) { + if (*p == 'w' || *p == 'a' || *p == '+') { + return true; + } + } + return false; +} + +CFileStream::CFileStream(const char* path, const char* mode) + : Stream(true, ModeCanRead(mode), ModeCanWrite(mode)), + file_(std::fopen(path, mode)), + auto_close_(true) { + if (file_ == nullptr) { + throw ErrnoException(u"Cannot open file."); + } +} + +CFileStream::CFileStream(std::FILE* file, bool readable, bool writable, + bool auto_close) + : Stream(true, readable, writable), file_(file), auto_close_(auto_close) { + if (file_ == nullptr) { + throw Exception(u"File is NULL."); + } +} + +CFileStream::~CFileStream() { + if (auto_close_ && file_ != nullptr) { + std::fclose(file_); + } +} + +static int ConvertOriginFlag(Stream::SeekOrigin origin) { + switch (origin) { + case Stream::SeekOrigin::Begin: + return SEEK_SET; + case Stream::SeekOrigin::Current: + return SEEK_CUR; + case Stream::SeekOrigin::End: + return SEEK_END; + default: + throw Exception(u"Unknown seek origin."); + } +} + +Index CFileStream::DoSeek(Index offset, SeekOrigin origin) { + if (std::fseek(file_, offset, ConvertOriginFlag(origin))) { + throw ErrnoException(u"Seek failed."); + } + return DoTell(); +} + +Index CFileStream::DoTell() { + long position = std::ftell(file_); + if (position == -1) { + throw ErrnoException(u"Tell failed."); + } + return position; +} + +void CFileStream::DoRewind() { std::rewind(file_); } + +Index CFileStream::DoRead(std::byte* buffer, Index offset, Index size) { + auto count = std::fread(buffer + offset, 1, size, file_); + return count; +} + +Index CFileStream::DoWrite(const std::byte* buffer, Index offset, Index size) { + auto count = std::fwrite(buffer + offset, 1, size, file_); + return count; +} + +void CFileStream::DoFlush() { std::fflush(file_); } + +void CFileStream::DoClose() { + CRU_STREAM_BEGIN_CLOSE + std::fclose(file_); + file_ = nullptr; +} +} // namespace cru::io diff --git a/src/base/io/MemoryStream.cpp b/src/base/io/MemoryStream.cpp new file mode 100644 index 00000000..4c650f3e --- /dev/null +++ b/src/base/io/MemoryStream.cpp @@ -0,0 +1,74 @@ +#include "cru/base/io/MemoryStream.h" + +#include +#include "cru/base/Exception.h" +#include "cru/base/io/Stream.h" + +namespace cru::io { +MemoryStream::MemoryStream( + std::byte* buffer, Index size, bool read_only, + std::function release_func) + : Stream(true, true, !read_only), + buffer_(buffer), + size_(size), + position_(0), + release_func_(std::move(release_func)) { + if (!buffer) { + throw Exception(u"Buffer is nullptr"); + } + if (size <= 0) { + throw Exception(u"Size is 0 or negative."); + } +} + +MemoryStream::~MemoryStream() {} + +void MemoryStream::Close() { DoClose(); } + +Index MemoryStream::DoSeek(Index offset, SeekOrigin origin) { + switch (origin) { + case SeekOrigin::Current: + position_ += offset; + break; + case SeekOrigin::Begin: + position_ = offset; + break; + case SeekOrigin::End: + position_ = size_ + offset; + break; + } + return position_; +} + +Index MemoryStream::DoRead(std::byte* buffer, Index offset, Index size) { + if (position_ + size > size_) { + size = size_ - position_; + } + if (size <= 0) { + return 0; + } + std::memmove(buffer + offset, buffer_ + position_, size); + position_ += size; + return size; +} + +Index MemoryStream::DoWrite(const std::byte* buffer, Index offset, Index size) { + if (position_ + size > size_) { + size = size_ - position_; + } + if (size <= 0) { + return 0; + } + std::memmove(buffer_ + position_, buffer + offset, size); + position_ += size; + return size; +} + +void MemoryStream::DoClose() { + CRU_STREAM_BEGIN_CLOSE + release_func_(buffer_, size_); + buffer_ = nullptr; + release_func_ = {}; +} + +} // namespace cru::io diff --git a/src/base/io/OpenFileFlag.cpp b/src/base/io/OpenFileFlag.cpp new file mode 100644 index 00000000..47069b29 --- /dev/null +++ b/src/base/io/OpenFileFlag.cpp @@ -0,0 +1,19 @@ +#include "cru/base/io/OpenFileFlag.h" + +namespace cru::io { +bool CheckOpenFileFlag(OpenFileFlag flags) { + auto has = [flags](OpenFileFlag flag) { return flags & flag; }; + + if ((has(OpenFileFlags::Append) || has(OpenFileFlags::Truncate) || + has(OpenFileFlags::Create)) && + !has(OpenFileFlags::Write)) { + return false; + } + + if (has(OpenFileFlags::Truncate) && has(OpenFileFlags::Append)) { + return false; + } + + return true; +} +} // namespace cru::io diff --git a/src/base/io/ProxyStream.cpp b/src/base/io/ProxyStream.cpp new file mode 100644 index 00000000..de66169e --- /dev/null +++ b/src/base/io/ProxyStream.cpp @@ -0,0 +1,37 @@ +#include "cru/base/io/ProxyStream.h" +#include "cru/base/io/Stream.h" + +namespace cru::io { +ProxyStream::ProxyStream(ProxyStreamHandlers handlers) + : Stream(static_cast(handlers.seek), static_cast(handlers.read), + static_cast(handlers.write)), + handlers_(std::move(handlers)) {} + +ProxyStream::~ProxyStream() { DoClose(); } + +Index ProxyStream::DoSeek(Index offset, SeekOrigin origin) { + return handlers_.seek(offset, origin); +} + +Index ProxyStream::DoRead(std::byte* buffer, Index offset, Index size) { + return handlers_.read(buffer, offset, size); +} + +Index ProxyStream::DoWrite(const std::byte* buffer, Index offset, Index size) { + return handlers_.write(buffer, offset, size); +} + +void ProxyStream::DoFlush() { + if (handlers_.flush) { + handlers_.flush(); + } +} + +void ProxyStream::DoClose() { + CRU_STREAM_BEGIN_CLOSE + if (handlers_.close) { + handlers_.close(); + } + handlers_ = {}; +} +} // namespace cru::io diff --git a/src/base/io/Resource.cpp b/src/base/io/Resource.cpp new file mode 100644 index 00000000..d369b5f5 --- /dev/null +++ b/src/base/io/Resource.cpp @@ -0,0 +1,48 @@ +#include "cru/base/io/Resource.h" +#include "cru/base/Exception.h" +#include "cru/base/log/Logger.h" + +#if defined(CRU_PLATFORM_OSX) +#include +#elif defined(CRU_PLATFORM_WINDOWS) +#include +#endif + +#include + +namespace cru::io { +std::filesystem::path GetResourceDir() { + constexpr auto kLogTag = u"GetResourceDir"; + +#if defined(CRU_PLATFORM_OSX) + CFBundleRef main_bundle = CFBundleGetMainBundle(); + CFURLRef bundle_url = CFBundleCopyBundleURL(main_bundle); + CFStringRef cf_string_ref = + CFURLCopyFileSystemPath(bundle_url, kCFURLPOSIXPathStyle); + std::filesystem::path bundle_path( + CFStringGetCStringPtr(cf_string_ref, kCFStringEncodingUTF8)); + + CFRelease(bundle_url); + CFRelease(cf_string_ref); + + return bundle_path / "Contents/Resources"; +#elif defined(CRU_PLATFORM_WINDOWS) + wchar_t buffer[MAX_PATH]; + DWORD size = ::GetModuleFileNameW(nullptr, buffer, MAX_PATH); + std::filesystem::path module_path(buffer, buffer + size); + auto p = module_path; + while (p.has_parent_path()) { + p = p.parent_path(); + auto resource_dir_path = p / "assets"; + if (std::filesystem::exists(resource_dir_path) && + std::filesystem::is_directory(resource_dir_path)) { + return resource_dir_path; + } + } + + throw Exception(u"Failed to find resource directory."); +#else + throw Exception(u"Not implemented."); +#endif +} +} // namespace cru::io diff --git a/src/base/io/Stream.cpp b/src/base/io/Stream.cpp new file mode 100644 index 00000000..d65bac46 --- /dev/null +++ b/src/base/io/Stream.cpp @@ -0,0 +1,199 @@ +#include "cru/base/io/Stream.h" +#include "cru/base/Exception.h" +#include "cru/base/Format.h" + +#include + +namespace cru::io { +StreamOperationNotSupportedException::StreamOperationNotSupportedException( + String operation) + : operation_(std::move(operation)) { + SetMessage(Format(u"Stream operation {} not supported.", operation_)); +} + +void StreamOperationNotSupportedException::CheckSeek(bool seekable) { + if (!seekable) throw StreamOperationNotSupportedException(u"seek"); +} + +void StreamOperationNotSupportedException::CheckRead(bool readable) { + if (!readable) throw StreamOperationNotSupportedException(u"read"); +} + +void StreamOperationNotSupportedException::CheckWrite(bool writable) { + if (!writable) throw StreamOperationNotSupportedException(u"write"); +} + +StreamAlreadyClosedException::StreamAlreadyClosedException() + : Exception(u"Stream is already closed.") {} + +void StreamAlreadyClosedException::Check(bool closed) { + if (closed) throw StreamAlreadyClosedException(); +} + +Stream::Stream(SupportedOperations supported_operations) + : supported_operations_(std::move(supported_operations)), closed_(false) {} + +Stream::Stream(std::optional can_seek, std::optional can_read, + std::optional can_write) + : Stream(SupportedOperations{can_seek, can_read, can_write}) {} + +bool Stream::CanSeek() { + CheckClosed(); + return DoCanSeek(); +} + +Index Stream::Seek(Index offset, SeekOrigin origin) { + CheckClosed(); + StreamOperationNotSupportedException::CheckSeek(DoCanSeek()); + return DoSeek(offset, origin); +} + +Index Stream::Tell() { + CheckClosed(); + return DoTell(); +} + +void Stream::Rewind() { + CheckClosed(); + return DoRewind(); +} + +Index Stream::GetSize() { + CheckClosed(); + return DoGetSize(); +} + +bool Stream::CanRead() { + CheckClosed(); + return DoCanRead(); +} + +Index Stream::Read(std::byte* buffer, Index offset, Index size) { + CheckClosed(); + StreamOperationNotSupportedException::CheckRead(DoCanRead()); + return DoRead(buffer, offset, size); +} + +Index Stream::Read(std::byte* buffer, Index size) { + return Read(buffer, 0, size); +} + +Index Stream::Read(char* buffer, Index offset, Index size) { + return Read(reinterpret_cast(buffer), offset, size); +} + +Index Stream::Read(char* buffer, Index size) { + return Read(reinterpret_cast(buffer), 0, size); +} + +bool Stream::CanWrite() { + CheckClosed(); + return DoCanWrite(); +} + +Index Stream::Write(const std::byte* buffer, Index offset, Index size) { + CheckClosed(); + StreamOperationNotSupportedException::CheckWrite(DoCanWrite()); + return DoWrite(buffer, offset, size); +} + +Index Stream::Write(const std::byte* buffer, Index size) { + return Write(buffer, 0, size); +} + +Index Stream::Write(const char* buffer, Index offset, Index size) { + return Write(reinterpret_cast(buffer), offset, size); +} + +Index Stream::Write(const char* buffer, Index size) { + return Write(reinterpret_cast(buffer), size); +} + +void Stream::Flush() { + CheckClosed(); + DoFlush(); +} + +bool Stream::DoCanSeek() { + if (supported_operations_->can_seek) { + return *supported_operations_->can_seek; + } else { + throw Exception( + u"Can seek is neither set in supported_operations nor implemeted in " + u"virtual function."); + } +} + +bool Stream::DoCanRead() { + if (supported_operations_->can_read) { + return *supported_operations_->can_read; + } else { + throw Exception( + u"Can read is neither set in supported_operations nor implemeted in " + u"virtual function."); + } +} + +bool Stream::DoCanWrite() { + if (supported_operations_->can_write) { + return *supported_operations_->can_write; + } else { + throw Exception( + u"Can write is neither set in supported_operations nor implemeted in " + u"virtual function."); + } +} + +Index Stream::DoSeek(Index offset, SeekOrigin origin) { + throw Exception(u"Stream is seekable but DoSeek is not implemented."); +} + +Index Stream::DoTell() { + StreamOperationNotSupportedException::CheckSeek(DoCanSeek()); + return DoSeek(0, SeekOrigin::Current); +} + +void Stream::DoRewind() { + StreamOperationNotSupportedException::CheckSeek(DoCanSeek()); + DoSeek(0, SeekOrigin::Begin); +} + +Index Stream::DoGetSize() { + StreamOperationNotSupportedException::CheckSeek(DoCanSeek()); + Index current_position = DoTell(); + Seek(0, SeekOrigin::End); + Index size = DoTell(); + Seek(current_position, SeekOrigin::Begin); + return size; +} + +Index Stream::DoRead(std::byte* buffer, Index offset, Index size) { + throw Exception(u"Stream is readable but DoSeek is not implemented."); +} + +Index Stream::DoWrite(const std::byte* buffer, Index offset, Index size) { + throw Exception(u"Stream is writable but DoSeek is not implemented."); +} + +void Stream::DoFlush() {} + +Buffer Stream::ReadToEnd(Index grow_size) { + Buffer buffer(grow_size); + while (true) { + auto read = Read(buffer.GetUsedEndPtr(), buffer.GetBackFree()); + buffer.PushBackCount(read); + if (read == 0) { + break; + } + if (buffer.IsUsedReachEnd()) { + buffer.ResizeBuffer(buffer.GetBufferSize() + grow_size, true); + } + } + return buffer; +} + +String Stream::ReadToEndAsUtf8String() { + auto buffer = ReadToEnd(); + return String::FromUtf8(buffer); +} +} // namespace cru::io diff --git a/src/base/log/Logger.cpp b/src/base/log/Logger.cpp new file mode 100644 index 00000000..86c65dbc --- /dev/null +++ b/src/base/log/Logger.cpp @@ -0,0 +1,88 @@ +#include "cru/base/log/Logger.h" +#include "cru/base/log/StdioLogTarget.h" + +#include +#include + +#ifdef CRU_PLATFORM_WINDOWS +#include "cru/base/platform/win/DebugLogTarget.h" +#endif + +namespace cru::log { +Logger *Logger::GetInstance() { + static Logger logger; + + logger.AddLogTarget(std::make_unique()); + +#ifdef CRU_PLATFORM_WINDOWS + logger.AddLogTarget(std::make_unique()); +#endif + + return &logger; +} + +void Logger::AddLogTarget(std::unique_ptr target) { + std::lock_guard lock(target_list_mutex_); + target_list_.push_back(std::move(target)); +} + +void Logger::RemoveLogTarget(ILogTarget *target) { + std::lock_guard lock(target_list_mutex_); + target_list_.erase( + std::remove_if(target_list_.begin(), target_list_.end(), + [target](const auto &t) { return t.get() == target; }), + target_list_.end()); +} + +namespace { +String LogLevelToString(LogLevel level) { + switch (level) { + case LogLevel::Debug: + return u"DEBUG"; + case LogLevel::Info: + return u"INFO"; + case LogLevel::Warn: + return u"WARN"; + case LogLevel::Error: + return u"ERROR"; + default: + std::terminate(); + } +} + +String GetLogTime() { + auto time = std::time(nullptr); + auto calendar = std::localtime(&time); + return Format(u"{}:{}:{}", calendar->tm_hour, calendar->tm_min, + calendar->tm_sec); +} + +String MakeLogFinalMessage(const LogInfo &log_info) { + return Format(u"[{}] {} {}: {}\n", GetLogTime(), + LogLevelToString(log_info.level), log_info.tag, + log_info.message); +} +} // namespace + +Logger::Logger() + : log_thread_([this] { + while (true) { + auto log_info = log_queue_.Pull(); + std::lock_guard lock_guard{target_list_mutex_}; + for (const auto &target : target_list_) { + target->Write(log_info.level, MakeLogFinalMessage(log_info)); + } + } + }) {} + +Logger::~Logger() { log_thread_.detach(); } + +void Logger::Log(LogInfo log_info) { +#ifndef CRU_DEBUG + if (log_info.level == LogLevel::Debug) { + return; + } +#endif + log_queue_.Push(std::move(log_info)); +} +} // namespace cru::log diff --git a/src/base/log/StdioLogTarget.cpp b/src/base/log/StdioLogTarget.cpp new file mode 100644 index 00000000..64ddcacc --- /dev/null +++ b/src/base/log/StdioLogTarget.cpp @@ -0,0 +1,27 @@ +#include "cru/base/log/StdioLogTarget.h" + +#include + +namespace cru::log { +StdioLogTarget::StdioLogTarget() {} + +StdioLogTarget::~StdioLogTarget() {} + +void StdioLogTarget::Write(log::LogLevel level, StringView s) { +#ifdef CRU_PLATFORM_WINDOWS + if (level == log::LogLevel::Error) { + std::wcerr.write(reinterpret_cast(s.data()), s.size()); + } else { + std::wcout.write(reinterpret_cast(s.data()), s.size()); + } +#else + std::string m = s.ToUtf8(); + + if (level == log::LogLevel::Error) { + std::cerr << m; + } else { + std::cout << m; + } +#endif +} +} // namespace cru::log diff --git a/src/base/platform/Exception.cpp b/src/base/platform/Exception.cpp new file mode 100644 index 00000000..b5e8c5b9 --- /dev/null +++ b/src/base/platform/Exception.cpp @@ -0,0 +1 @@ +#include "cru/base/platform/Exception.h" diff --git a/src/base/platform/osx/Convert.cpp b/src/base/platform/osx/Convert.cpp new file mode 100644 index 00000000..1a6deb8f --- /dev/null +++ b/src/base/platform/osx/Convert.cpp @@ -0,0 +1,29 @@ +#include "cru/base/platform/osx/Convert.h" + +namespace cru::platform::osx { +CFStringRef Convert(const String& string) { + return CFStringCreateWithBytes( + nullptr, reinterpret_cast(string.data()), + string.size() * sizeof(std::uint16_t), kCFStringEncodingUTF16, false); +} + +String Convert(CFStringRef string) { + auto length = CFStringGetLength(string); + + String result; + + for (int i = 0; i < length; i++) { + result.AppendCodePoint(CFStringGetCharacterAtIndex(string, i)); + } + + return result; +} + +CFRange Convert(const Range& range) { + return CFRangeMake(range.position, range.count); +} + +Range Convert(const CFRange& range) { + return Range(range.location, range.length); +} +} // namespace cru::platform::osx diff --git a/src/base/platform/osx/Exception.cpp b/src/base/platform/osx/Exception.cpp new file mode 100644 index 00000000..a60448dd --- /dev/null +++ b/src/base/platform/osx/Exception.cpp @@ -0,0 +1 @@ +#include "cru/base/platform//osx/Exception.h" diff --git a/src/base/platform/unix/PosixSpawnSubProcess.cpp b/src/base/platform/unix/PosixSpawnSubProcess.cpp new file mode 100644 index 00000000..75d48cc2 --- /dev/null +++ b/src/base/platform/unix/PosixSpawnSubProcess.cpp @@ -0,0 +1,204 @@ +#include "cru/base/platform/unix/PosixSpawnSubProcess.h" +#include "cru/base/Exception.h" +#include "cru/base/Format.h" +#include "cru/base/Guard.h" +#include "cru/base/String.h" +#include "cru/base/SubProcess.h" +#include "cru/base/log/Logger.h" + +#include +#include +#include +#include +#include +#include + +namespace cru::platform::unix { +PosixSpawnSubProcessImpl::PosixSpawnSubProcessImpl() + : pid_(0), + exit_code_(0), + stdin_pipe_(UnixPipe::Usage::Send, false), + stdout_pipe_(UnixPipe::Usage::Receive, false), + stderr_pipe_(UnixPipe::Usage::Receive, false) { + stdin_stream_ = std::make_unique( + stdin_pipe_.GetSelfFileDescriptor(), false, false, true, true); + stdout_stream_ = std::make_unique( + stdout_pipe_.GetSelfFileDescriptor(), false, true, false, true); + stderr_stream_ = std::make_unique( + stderr_pipe_.GetSelfFileDescriptor(), false, true, false, true); + + stdout_buffer_stream_ = + std::make_unique(stdout_stream_.get(), false); + stderr_buffer_stream_ = + std::make_unique(stderr_stream_.get(), false); +} + +PosixSpawnSubProcessImpl::~PosixSpawnSubProcessImpl() {} + +namespace { +char** CreateCstrArray(const std::vector& argv) { + std::vector utf8_argv; + for (const auto& arg : argv) { + utf8_argv.push_back(arg.ToUtf8Buffer()); + } + char** result = new char*[utf8_argv.size() + 1]; + for (int i = 0; i < utf8_argv.size(); i++) { + result[i] = reinterpret_cast(utf8_argv[i].Detach()); + } + result[utf8_argv.size()] = nullptr; + return result; +} + +char** CreateCstrArray(const std::unordered_map& envp) { + std::vector str_array; + for (auto& [key, value] : envp) { + str_array.push_back(cru::Format(u"{}={}", key, value)); + } + return CreateCstrArray(str_array); +} + +void DestroyCstrArray(char** argv) { + int index = 0; + char* arg = argv[index]; + while (arg) { + delete[] arg; + index++; + arg = argv[index]; + } + delete[] argv; +} +} // namespace + +void PosixSpawnSubProcessImpl::PlatformCreateProcess( + const SubProcessStartInfo& start_info) { + int error; + auto check_error = [&error](String message) { + if (error == 0) return; + std::unique_ptr inner(new ErrnoException({}, error)); + throw SubProcessFailedToStartException(std::move(message), + std::move(inner)); + }; + + posix_spawn_file_actions_t file_actions; + error = posix_spawn_file_actions_init(&file_actions); + check_error(u"Failed to call posix_spawn_file_actions_init."); + Guard file_actions_guard( + [&file_actions] { posix_spawn_file_actions_destroy(&file_actions); }); + + // dup2 stdin/stdout/stderr + error = posix_spawn_file_actions_adddup2( + &file_actions, stdin_pipe_.GetOtherFileDescriptor(), STDIN_FILENO); + check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdin."); + error = posix_spawn_file_actions_adddup2( + &file_actions, stdout_pipe_.GetOtherFileDescriptor(), STDOUT_FILENO); + check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdout."); + error = posix_spawn_file_actions_adddup2( + &file_actions, stderr_pipe_.GetOtherFileDescriptor(), STDERR_FILENO); + check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stderr."); + + error = posix_spawn_file_actions_addclose( + &file_actions, stdin_pipe_.GetOtherFileDescriptor()); + check_error( + u"Failed to call posix_spawn_file_actions_addclose on self fd of stdin."); + error = posix_spawn_file_actions_addclose( + &file_actions, stdout_pipe_.GetOtherFileDescriptor()); + check_error( + u"Failed to call posix_spawn_file_actions_addclose on self fd stdout."); + error = posix_spawn_file_actions_addclose( + &file_actions, stderr_pipe_.GetOtherFileDescriptor()); + check_error( + u"Failed to call posix_spawn_file_actions_addclose on self fd stderr."); + + error = posix_spawn_file_actions_addclose( + &file_actions, stdin_pipe_.GetSelfFileDescriptor()); + check_error( + u"Failed to call posix_spawn_file_actions_addclose on parent fd of " + u"stdin."); + error = posix_spawn_file_actions_addclose( + &file_actions, stdout_pipe_.GetSelfFileDescriptor()); + check_error( + u"Failed to call posix_spawn_file_actions_addclose on parent fd of " + u"stdout."); + error = posix_spawn_file_actions_addclose( + &file_actions, stderr_pipe_.GetSelfFileDescriptor()); + check_error( + u"Failed to call posix_spawn_file_actions_addclose on parent fd of " + u"stderr."); + + posix_spawnattr_t attr; + error = posix_spawnattr_init(&attr); + check_error(u"Failed to call posix_spawnattr_init."); + Guard attr_guard([&attr] { posix_spawnattr_destroy(&attr); }); + +#ifdef CRU_PLATFORM_OSX + error = posix_spawnattr_setflags(&attr, POSIX_SPAWN_CLOEXEC_DEFAULT); + check_error(u"Failed to set flag POSIX_SPAWN_CLOEXEC_DEFAULT (osx)."); +#endif + + auto exe = start_info.program.ToUtf8(); + std::vector arguments{start_info.program}; + arguments.insert(arguments.cend(), start_info.arguments.cbegin(), + start_info.arguments.cend()); + + auto argv = CreateCstrArray(arguments); + Guard argv_guard([argv] { DestroyCstrArray(argv); }); + + auto envp = CreateCstrArray(start_info.environments); + Guard envp_guard([envp] { DestroyCstrArray(envp); }); + + error = posix_spawnp(&pid_, exe.c_str(), &file_actions, &attr, argv, envp); + check_error(u"Failed to call posix_spawnp."); + + error = ::close(stdin_pipe_.GetOtherFileDescriptor()); + check_error(u"Failed to close child stdin."); + error = ::close(stdout_pipe_.GetOtherFileDescriptor()); + check_error(u"Failed to close child stdout."); + error = ::close(stderr_pipe_.GetOtherFileDescriptor()); + check_error(u"Failed to close child stderr."); +} + +SubProcessExitResult PosixSpawnSubProcessImpl::PlatformWaitForProcess() { + int wstatus; + + while (waitpid(pid_, &wstatus, 0) == -1) { + if (errno == EINTR) { + CRU_LOG_INFO(u"Waitpid is interrupted by a signal. Call it again."); + continue; + } + + std::unique_ptr inner(new ErrnoException({}, errno)); + + throw SubProcessInternalException( + u"Failed to call waitpid on a subprocess.", std::move(inner)); + } + + if (WIFEXITED(wstatus)) { + return SubProcessExitResult::Normal(WEXITSTATUS(wstatus)); + } else if (WIFEXITED(wstatus)) { + return SubProcessExitResult::Signal(WTERMSIG(wstatus), WCOREDUMP(wstatus)); + } else { + return SubProcessExitResult::Unknown(); + } +} + +void PosixSpawnSubProcessImpl::PlatformKillProcess() { + int error = kill(pid_, SIGKILL); + if (error != 0) { + std::unique_ptr inner(new ErrnoException({}, errno)); + throw SubProcessInternalException(u"Failed to call kill on a subprocess.", + std::move(inner)); + } +} + +io::Stream* PosixSpawnSubProcessImpl::GetStdinStream() { + return stdin_stream_.get(); +} + +io::Stream* PosixSpawnSubProcessImpl::GetStdoutStream() { + return stdout_buffer_stream_.get(); +} + +io::Stream* PosixSpawnSubProcessImpl::GetStderrStream() { + return stderr_buffer_stream_.get(); +} +} // namespace cru::platform::unix diff --git a/src/base/platform/unix/UnixFileStream.cpp b/src/base/platform/unix/UnixFileStream.cpp new file mode 100644 index 00000000..c53bbbaa --- /dev/null +++ b/src/base/platform/unix/UnixFileStream.cpp @@ -0,0 +1,106 @@ +#include "cru/base/platform/unix/UnixFileStream.h" +#include "cru/base/Exception.h" +#include "cru/base/Format.h" +#include "cru/base/io/Stream.h" +#include "cru/base/log/Logger.h" + +#include +#include +#include +#include + +namespace cru::platform::unix { +using namespace cru::io; + +namespace { +bool OflagCanSeek([[maybe_unused]] int oflag) { + // Treat every file seekable. + return true; +} + +bool OflagCanRead(int oflag) { + // There is a problem: O_RDONLY is 0. So we must test it specially. + // If it is not write-only. Then it can read. + return !(oflag & O_WRONLY); +} + +bool OflagCanWrite(int oflag) { return oflag & O_WRONLY || oflag & O_RDWR; } + +int MapSeekOrigin(Stream::SeekOrigin origin) { + switch (origin) { + case Stream::SeekOrigin::Begin: + return SEEK_SET; + case Stream::SeekOrigin::Current: + return SEEK_CUR; + case Stream::SeekOrigin::End: + return SEEK_END; + default: + throw Exception(u"Invalid seek origin."); + } +} +} // namespace + +UnixFileStream::UnixFileStream(const char *path, int oflag, mode_t mode) { + file_descriptor_ = ::open(path, oflag, mode); + if (file_descriptor_ == -1) { + throw ErrnoException( + Format(u"Failed to open file {} with oflag {}, mode {}.", + String::FromUtf8(path), oflag, mode)); + } + + SetSupportedOperations( + {OflagCanSeek(oflag), OflagCanRead(oflag), OflagCanWrite(oflag)}); + + auto_close_ = true; +} + +UnixFileStream::UnixFileStream(int fd, bool can_seek, bool can_read, + bool can_write, bool auto_close) + : Stream(can_seek, can_read, can_write) { + file_descriptor_ = fd; + auto_close_ = auto_close; +} + +UnixFileStream::~UnixFileStream() { + if (auto_close_ && file_descriptor_ >= 0) { + if (::close(file_descriptor_) == -1) { + // We are in destructor, so we can not throw. + CRU_LOG_WARN(u"Failed to close file descriptor {}, errno {}.", + file_descriptor_, errno); + } + } +} + +Index UnixFileStream::DoSeek(Index offset, SeekOrigin origin) { + off_t result = ::lseek(file_descriptor_, offset, MapSeekOrigin(origin)); + if (result == -1) { + throw ErrnoException(u"Failed to seek file."); + } + return result; +} + +Index UnixFileStream::DoRead(std::byte *buffer, Index offset, Index size) { + auto result = ::read(file_descriptor_, buffer + offset, size); + if (result == -1) { + throw ErrnoException(u"Failed to read file."); + } + return result; +} + +Index UnixFileStream::DoWrite(const std::byte *buffer, Index offset, + Index size) { + auto result = ::write(file_descriptor_, buffer + offset, size); + if (result == -1) { + throw ErrnoException(u"Failed to write file."); + } + return result; +} + +void UnixFileStream::DoClose() { + CRU_STREAM_BEGIN_CLOSE + if (auto_close_ && ::close(file_descriptor_) == -1) { + throw ErrnoException(u"Failed to close file."); + } + file_descriptor_ = -1; +} +} // namespace cru::platform::unix diff --git a/src/base/platform/unix/UnixPipe.cpp b/src/base/platform/unix/UnixPipe.cpp new file mode 100644 index 00000000..747efe94 --- /dev/null +++ b/src/base/platform/unix/UnixPipe.cpp @@ -0,0 +1,51 @@ +#include "cru/base/platform/unix/UnixPipe.h" +#include "cru/base/Exception.h" +#include "cru/base/log/Logger.h" + +#include +#include +#include + +namespace cru::platform::unix { +UnixPipe::UnixPipe(Usage usage, bool auto_close, UnixPipeFlag flags) + : usage_(usage), auto_close_(auto_close), flags_(flags) { + int fds[2]; + if (pipe(fds) != 0) { + throw ErrnoException(u"Failed to create unix pipe."); + } + + if (flags & UnixPipeFlags::NonBlock) { + fcntl(fds[0], F_SETFL, O_NONBLOCK); + fcntl(fds[1], F_SETFL, O_NONBLOCK); + } + + read_fd_ = fds[0]; + write_fd_ = fds[1]; +} + +int UnixPipe::GetSelfFileDescriptor() { + if (usage_ == Usage::Send) { + return write_fd_; + } else { + return read_fd_; + } +} + +int UnixPipe::GetOtherFileDescriptor() { + if (usage_ == Usage::Send) { + return read_fd_; + } else { + return write_fd_; + } +} + +UnixPipe::~UnixPipe() { + if (auto_close_) { + auto self_fd = GetSelfFileDescriptor(); + if (::close(self_fd) != 0) { + CRU_LOG_ERROR(u"Failed to close unix pipe file descriptor {}, errno {}.", + self_fd, errno); + } + } +} +} // namespace cru::platform::unix diff --git a/src/base/platform/web/WebException.cpp b/src/base/platform/web/WebException.cpp new file mode 100644 index 00000000..f473bb5b --- /dev/null +++ b/src/base/platform/web/WebException.cpp @@ -0,0 +1 @@ +#include "cru/base/platform/web/WebException.h" diff --git a/src/base/platform/win/BridgeComStream.cpp b/src/base/platform/win/BridgeComStream.cpp new file mode 100644 index 00000000..c6987ab2 --- /dev/null +++ b/src/base/platform/win/BridgeComStream.cpp @@ -0,0 +1,106 @@ +#include "BrigdeComStream.h" +#include "cru/base/io/Stream.h" + +namespace cru::platform::win { +BridgeComStream::BridgeComStream(io::Stream *stream) + : stream_(stream), ref_count_(1) {} + +BridgeComStream::~BridgeComStream() {} + +ULONG BridgeComStream::AddRef() { return ++ref_count_; } + +ULONG BridgeComStream::Release() { + --ref_count_; + + if (ref_count_ == 0) { + delete this; + return 0; + } + + return ref_count_; +} + +HRESULT BridgeComStream::QueryInterface(const IID &riid, void **ppvObject) { + if (riid == IID_IStream) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } else if (riid == IID_ISequentialStream) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } else if (riid == IID_IUnknown) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } else { + return E_NOINTERFACE; + } +} + +HRESULT BridgeComStream::Read(void *pv, ULONG cb, ULONG *pcbRead) { + *pcbRead = stream_->Read(static_cast(pv), cb); + return S_OK; +} + +HRESULT BridgeComStream::Write(const void *pv, ULONG cb, ULONG *pcbWritten) { + *pcbWritten = stream_->Write(static_cast(pv), cb); + return S_OK; +} + +HRESULT BridgeComStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, + ULARGE_INTEGER *plibNewPosition) { + io::Stream::SeekOrigin so; + + switch (dwOrigin) { + case STREAM_SEEK_SET: + so = io::Stream::SeekOrigin::Begin; + break; + case STREAM_SEEK_CUR: + so = io::Stream::SeekOrigin::Current; + break; + case STREAM_SEEK_END: + so = io::Stream::SeekOrigin::End; + break; + default: + return STG_E_INVALIDFUNCTION; + }; + + plibNewPosition->QuadPart = stream_->Seek(dlibMove.QuadPart, so); + return S_OK; +} + +HRESULT BridgeComStream::SetSize(ULARGE_INTEGER libNewSize) { + return E_NOTIMPL; +} + +HRESULT BridgeComStream::CopyTo(IStream *pstm, ULARGE_INTEGER cb, + ULARGE_INTEGER *pcbRead, + ULARGE_INTEGER *pcbWritten) { + return E_NOTIMPL; +} + +HRESULT BridgeComStream::Commit(DWORD grfCommitFlags) { return S_OK; } + +HRESULT BridgeComStream::Revert() { return S_OK; } + +HRESULT BridgeComStream::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, + DWORD dwLockType) { + return S_OK; +} + +HRESULT BridgeComStream::UnlockRegion(ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, DWORD dwLockType) { + return S_OK; +} + +HRESULT BridgeComStream::Stat(STATSTG *pstatstg, DWORD grfStatFlag) { + return E_NOTIMPL; +} + +HRESULT BridgeComStream::Clone(IStream **ppstm) { + *ppstm = new BridgeComStream(stream_); + return S_OK; +} + +} // namespace cru::platform::win diff --git a/src/base/platform/win/BrigdeComStream.h b/src/base/platform/win/BrigdeComStream.h new file mode 100644 index 00000000..1621b567 --- /dev/null +++ b/src/base/platform/win/BrigdeComStream.h @@ -0,0 +1,43 @@ +#pragma once +#include "cru/base/platform/win/WinPreConfig.h" + +#include "cru/base/io/Stream.h" + +#include + +namespace cru::platform::win { +class BridgeComStream : public IStream { + public: + explicit BridgeComStream(io::Stream* stream); + + CRU_DELETE_COPY(BridgeComStream) + CRU_DELETE_MOVE(BridgeComStream) + + ~BridgeComStream(); + + public: + ULONG AddRef() override; + ULONG Release() override; + HRESULT QueryInterface(REFIID riid, void** ppvObject) override; + + HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) override; + HRESULT Write(const void* pv, ULONG cb, ULONG* pcbWritten) override; + HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, + ULARGE_INTEGER* plibNewPosition) override; + HRESULT SetSize(ULARGE_INTEGER libNewSize) override; + HRESULT CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, + ULARGE_INTEGER* pcbWritten) override; + HRESULT Commit(DWORD grfCommitFlags) override; + HRESULT Revert() override; + HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, + DWORD dwLockType) override; + HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, + DWORD dwLockType) override; + HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) override; + HRESULT Clone(IStream** ppstm) override; + + private: + io::Stream* stream_; + ULONG ref_count_; +}; +} // namespace cru::platform::win diff --git a/src/base/platform/win/ComAutoInit.cpp b/src/base/platform/win/ComAutoInit.cpp new file mode 100644 index 00000000..548a7bea --- /dev/null +++ b/src/base/platform/win/ComAutoInit.cpp @@ -0,0 +1,15 @@ +#include "cru/base/platform/win/ComAutoInit.h" +#include "cru/base/platform/win/Exception.h" + +#include + +namespace cru::platform::win { +ComAutoInit::ComAutoInit() { + const auto hresult = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + if (FAILED(hresult)) { + throw HResultError(hresult, "Failed to call CoInitializeEx."); + } +} + +ComAutoInit::~ComAutoInit() { ::CoUninitialize(); } +} // namespace cru::platform::win diff --git a/src/base/platform/win/DebugLogTarget.cpp b/src/base/platform/win/DebugLogTarget.cpp new file mode 100644 index 00000000..89bd3d19 --- /dev/null +++ b/src/base/platform/win/DebugLogTarget.cpp @@ -0,0 +1,10 @@ +#include "cru/base/platform/win/DebugLogTarget.h" + +namespace cru::platform::win { +void WinDebugLogTarget::Write(::cru::log::LogLevel level, StringView s) { + CRU_UNUSED(level) + + String m = s.ToString(); + ::OutputDebugStringW(reinterpret_cast(m.c_str())); +} +} // namespace cru::platform::win diff --git a/src/base/platform/win/Exception.cpp b/src/base/platform/win/Exception.cpp new file mode 100644 index 00000000..5ff6146b --- /dev/null +++ b/src/base/platform/win/Exception.cpp @@ -0,0 +1,38 @@ +#include "cru/base/platform/win/Exception.h" +#include "cru/base/Format.h" + +#include + +namespace cru::platform::win { + +inline String HResultMakeMessage(HRESULT h_result, + std::optional message) { + if (message.has_value()) + return Format(u"HRESULT: {}. Message: {}", h_result, message->WinCStr()); + else + return Format(u"HRESULT: {}.", h_result); +} + +HResultError::HResultError(HRESULT h_result) + : PlatformException(HResultMakeMessage(h_result, std::nullopt)), + h_result_(h_result) {} + +HResultError::HResultError(HRESULT h_result, + std::string_view additional_message) + : PlatformException(HResultMakeMessage( + h_result, String::FromUtf8(additional_message.data(), + additional_message.size()))), + h_result_(h_result) {} + +inline String Win32MakeMessage(DWORD error_code, String message) { + return Format(u"Last error code: {}.\nMessage: {}\n", error_code, + message.WinCStr()); +} + +Win32Error::Win32Error(String message) + : Win32Error(::GetLastError(), message) {} + +Win32Error::Win32Error(DWORD error_code, String message) + : PlatformException(Win32MakeMessage(error_code, message)), + error_code_(error_code) {} +} // namespace cru::platform::win diff --git a/src/base/platform/win/StreamConvert.cpp b/src/base/platform/win/StreamConvert.cpp new file mode 100644 index 00000000..f7a0537c --- /dev/null +++ b/src/base/platform/win/StreamConvert.cpp @@ -0,0 +1,28 @@ +#include "cru/base/platform/win/StreamConvert.h" +#include "BrigdeComStream.h" +#include "Win32FileStreamPrivate.h" +#include "cru/base/Exception.h" +#include "cru/base/io/MemoryStream.h" +#include "cru/base/io/OpenFileFlag.h" +#include "cru/base/platform/win/ComAutoInit.h" +#include "cru/base/platform/win/Exception.h" +#include "cru/base/platform/win/Win32FileStream.h" + +#include +#include + +namespace cru::platform::win { +IStream* ConvertStreamToComStream(io::Stream* stream) { + static ComAutoInit com_auto_init; + + if (auto memory_stream = dynamic_cast(stream)) { + return SHCreateMemStream( + reinterpret_cast(memory_stream->GetBuffer()), + memory_stream->GetSize()); + } else if (auto file_stream = dynamic_cast(stream)) { + return file_stream->GetPrivate_()->stream_; + } else { + return new BridgeComStream(stream); + } +} +} // namespace cru::platform::win diff --git a/src/base/platform/win/Win32FileStream.cpp b/src/base/platform/win/Win32FileStream.cpp new file mode 100644 index 00000000..54e6ae45 --- /dev/null +++ b/src/base/platform/win/Win32FileStream.cpp @@ -0,0 +1,122 @@ +#include "cru/base/platform/win/Win32FileStream.h" + +#include "Win32FileStreamPrivate.h" +#include "cru/base/io/OpenFileFlag.h" +#include "cru/base/platform/win/Exception.h" + +#include +#include +#include +#include +#include + +namespace cru::platform::win { +using namespace cru::io; + +Win32FileStream::Win32FileStream(String path, OpenFileFlag flags) + : path_(std::move(path)), + flags_(flags), + p_(new details::Win32FileStreamPrivate()) { + DWORD grfMode = STGM_SHARE_DENY_NONE; + if (flags & io::OpenFileFlags::Read) { + if (flags & io::OpenFileFlags::Write) { + grfMode |= STGM_READWRITE; + } else { + grfMode |= STGM_READ; + } + } else { + if (flags & io::OpenFileFlags::Write) { + grfMode |= STGM_WRITE; + } else { + throw Exception(u"Stream must be readable or writable."); + } + } + + if (flags & io::OpenFileFlags::Truncate) { + grfMode |= STGM_CREATE; + } + + IStream* stream; + + ThrowIfFailed(SHCreateStreamOnFileEx( + path_.WinCStr(), grfMode, FILE_ATTRIBUTE_NORMAL, + flags & io::OpenFileFlags::Create ? TRUE : FALSE, NULL, &stream)); + + p_->stream_ = stream; +} + +Win32FileStream::~Win32FileStream() { + Close(); + delete p_; +} + +bool Win32FileStream::CanSeek() { return true; } + +Index Win32FileStream::Seek(Index offset, SeekOrigin origin) { + CheckClosed(); + + DWORD dwOrigin = 0; + + if (origin == SeekOrigin::Current) { + dwOrigin = STREAM_SEEK_CUR; + } else if (origin == SeekOrigin::End) { + dwOrigin = STREAM_SEEK_END; + } else { + dwOrigin = STREAM_SEEK_SET; + } + + LARGE_INTEGER n_offset; + n_offset.QuadPart = offset; + ULARGE_INTEGER n_new_offset; + + ThrowIfFailed(p_->stream_->Seek(n_offset, dwOrigin, &n_new_offset)); + + return n_new_offset.QuadPart; +} + +bool Win32FileStream::CanRead() { return true; } + +Index Win32FileStream::Read(std::byte* buffer, Index offset, Index size) { + if (size < 0) { + throw Exception(u"Size must be greater than 0."); + } + + CheckClosed(); + + ULONG n_read; + ThrowIfFailed(p_->stream_->Read(buffer + offset, size, &n_read)); + return n_read; +} + +bool Win32FileStream::CanWrite() { return true; } + +Index Win32FileStream::Write(const std::byte* buffer, Index offset, + Index size) { + if (size < 0) { + throw Exception(u"Size must be greater than 0."); + } + + CheckClosed(); + + ULONG n_written; + ThrowIfFailed(p_->stream_->Write(buffer + offset, size, &n_written)); + + return n_written; +} + +void Win32FileStream::Close() { + if (closed_) return; + + if (p_->stream_) { + p_->stream_->Release(); + p_->stream_ = nullptr; + } + + closed_ = true; +} + +void Win32FileStream::CheckClosed() { + if (closed_) throw Exception(u"Stream is closed."); +} + +} // namespace cru::platform::win diff --git a/src/base/platform/win/Win32FileStreamPrivate.h b/src/base/platform/win/Win32FileStreamPrivate.h new file mode 100644 index 00000000..718f8d9a --- /dev/null +++ b/src/base/platform/win/Win32FileStreamPrivate.h @@ -0,0 +1,13 @@ +#include "cru/base/platform/win/WinPreConfig.h" + +#include + +namespace cru::platform::win { + +namespace details { +struct Win32FileStreamPrivate { + IStream* stream_ = nullptr; +}; +} // namespace details + +} // namespace cru::platform::win diff --git a/src/common/Base.cpp b/src/common/Base.cpp deleted file mode 100644 index ba4077b4..00000000 --- a/src/common/Base.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "cru/common/Base.h" - -#include - -namespace cru { -void UnreachableCode() { std::terminate(); } -} // namespace cru diff --git a/src/common/Buffer.cpp b/src/common/Buffer.cpp deleted file mode 100644 index 7b4248c7..00000000 --- a/src/common/Buffer.cpp +++ /dev/null @@ -1,277 +0,0 @@ -#include "cru/common/Buffer.h" -#include "cru/common/Exception.h" - -#include - -namespace cru { -namespace { -void CheckSize(Index size) { - if (size < 0) { - throw Exception(u"Size of buffer can't be smaller than 0."); - } -} -} // namespace - -Buffer::Buffer() { - ptr_ = nullptr; - size_ = used_begin_ = used_end_ = 0; -} - -Buffer::Buffer(Index size) { - CheckSize(size); - if (size == 0) { - ptr_ = nullptr; - size_ = used_begin_ = used_end_ = 0; - } else { - ptr_ = new std::byte[size]; - size_ = size; - used_begin_ = used_end_ = 0; - } - AssertValid(); -} - -Buffer::Buffer(const Buffer& other) { Copy_(other); } - -Buffer::Buffer(Buffer&& other) noexcept { Move_(std::move(other)); } - -Buffer& Buffer::operator=(const Buffer& other) { - if (this != &other) { - Delete_(); - Copy_(other); - } - return *this; -} - -Buffer& Buffer::operator=(Buffer&& other) noexcept { - if (this != &other) { - Delete_(); - Move_(std::move(other)); - } - return *this; -} - -Buffer::~Buffer() { Delete_(); } - -void Buffer::AssignBytes(Index dst_offset, std::byte* src, Index src_offset, - Index src_size, bool use_memmove) { - CheckSize(src_size); - - AssertValid(); - - (use_memmove ? std::memmove : std::memcpy)(ptr_ + dst_offset, - src + src_offset, src_size); - AssertValid(); -} - -void Buffer::ResizeBuffer(Index new_size, bool preserve_used) { - CheckSize(new_size); - - AssertValid(); - - if (new_size == 0) { - Delete_(); - ptr_ = nullptr; - size_ = used_begin_ = used_end_ = 0; - return; - } - - auto old_ptr = ptr_; - - ptr_ = new std::byte[new_size]; - size_ = new_size; - used_begin_ = std::min(new_size, used_begin_); - used_end_ = std::min(new_size, used_end_); - - if (old_ptr) { - if (preserve_used && used_begin_ < used_end_) { - std::memcpy(ptr_ + used_begin_, old_ptr + used_begin_, - used_end_ - used_begin_); - } - delete[] old_ptr; - } - - AssertValid(); -} - -Index Buffer::PushFront(const std::byte* other, Index other_size, - bool use_memmove) { - CheckSize(other_size); - - AssertValid(); - - auto copy_size = std::min(used_begin_, other_size); - - if (copy_size) { - used_begin_ -= copy_size; - (use_memmove ? std::memmove : std::memcpy)(ptr_ + used_begin_, other, - copy_size); - } - - AssertValid(); - - return copy_size; -} - -bool Buffer::PushBack(std::byte b) { - AssertValid(); - if (IsUsedReachEnd()) { - return false; - } - ptr_[used_end_] = b; - used_end_++; - AssertValid(); - return true; -} - -Index Buffer::PushBack(const std::byte* other, Index other_size, - bool use_memmove) { - CheckSize(other_size); - - AssertValid(); - - auto copy_size = std::min(size_ - used_end_, other_size); - - if (copy_size) { - (use_memmove ? std::memmove : std::memcpy)(ptr_ + used_end_, other, - copy_size); - used_end_ += copy_size; - } - - AssertValid(); - - return copy_size; -} - -void Buffer::PushBackCount(Index count) { - if (count < 0 || count > GetBackFree()) { - throw Exception(u"Count out of range in PushBackCount."); - } - used_end_ += count; -} - -Index Buffer::PopFront(Index size) { - CheckSize(size); - - AssertValid(); - - auto move = std::min(used_begin_, size); - used_begin_ -= move; - - AssertValid(); - - return move; -} - -Index Buffer::PopFront(std::byte* buffer, Index size, bool use_memmove) { - CheckSize(size); - - AssertValid(); - - auto pop_size = std::min(GetUsedSize(), size); - - if (pop_size) { - used_begin_ += pop_size; - (use_memmove ? std::memmove : std::memcpy)( - buffer, GetUsedBeginPtr() - pop_size, pop_size); - } - - AssertValid(); - - return pop_size; -} - -Index Buffer::PopEnd(Index size) { - CheckSize(size); - - AssertValid(); - - auto move = std::min(size_ - used_end_, size); - used_end_ += move; - - AssertValid(); - - return move; -} - -Index Buffer::PopEnd(std::byte* buffer, Index size, bool use_memmove) { - CheckSize(size); - - AssertValid(); - - auto pop_size = std::min(GetUsedSize(), size); - - if (pop_size) { - used_end_ -= pop_size; - (use_memmove ? std::memmove : std::memcpy)(buffer, GetUsedEndPtr(), - pop_size); - } - - AssertValid(); - - return pop_size; -} - -std::byte* Buffer::Detach(Index* size) { - AssertValid(); - - auto ptr = this->ptr_; - if (size) { - *size = this->size_; - } - this->ptr_ = nullptr; - this->size_ = this->used_begin_ = this->used_end_ = 0; - - AssertValid(); - - return ptr; -} - -void Buffer::Copy_(const Buffer& other) { - if (other.ptr_ == nullptr) { - ptr_ = nullptr; - size_ = used_begin_ = used_end_ = 0; - } else { - ptr_ = new std::byte[other.size_]; - size_ = other.size_; - used_begin_ = other.used_begin_; - used_end_ = other.used_end_; - std::memcpy(ptr_ + used_begin_, other.ptr_ + used_begin_, - used_end_ - used_begin_); - } - AssertValid(); -} - -void Buffer::Move_(Buffer&& other) noexcept { - ptr_ = other.ptr_; - size_ = other.size_; - used_begin_ = other.used_begin_; - used_end_ = other.used_end_; - other.ptr_ = nullptr; - other.size_ = other.used_begin_ = other.used_end_ = 0; - AssertValid(); -} - -void Buffer::Delete_() noexcept { - if (ptr_) { - delete[] ptr_; - } -} - -void Buffer::AssertValid() { - assert(size_ >= 0); - assert(used_begin_ >= 0); - assert(used_begin_ <= size_); - assert(used_end_ >= 0); - assert(used_end_ <= size_); - assert(used_end_ >= used_begin_); - assert((ptr_ == nullptr && size_ == 0) || (ptr_ != nullptr && size_ > 0)); -} - -void swap(Buffer& left, Buffer& right) noexcept { - using std::swap; - swap(left.ptr_, right.ptr_); - swap(left.size_, right.size_); - swap(left.used_begin_, right.used_begin_); - swap(left.used_end_, right.used_end_); -} -} // namespace cru diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt deleted file mode 100644 index 19feddba..00000000 --- a/src/common/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -add_library(CruBase - Base.cpp - Buffer.cpp - Exception.cpp - Format.cpp - PropertyTree.cpp - String.cpp - StringToNumberConverter.cpp - StringUtil.cpp - SubProcess.cpp - io/AutoReadStream.cpp - io/BufferStream.cpp - io/CFileStream.cpp - io/Stream.cpp - io/ProxyStream.cpp - io/Resource.cpp - io/MemoryStream.cpp - log/Logger.cpp - log/StdioLogTarget.cpp - platform/Exception.cpp -) -target_compile_definitions(CruBase PRIVATE CRU_BASE_EXPORT_API) -target_include_directories(CruBase PUBLIC ${CRU_INCLUDE_DIR}) -target_compile_definitions(CruBase PUBLIC $<$:CRU_DEBUG>) - -if (UNIX AND NOT EMSCRIPTEN) - target_sources(CruBase PRIVATE - platform/unix/PosixSpawnSubProcess.cpp - platform/unix/UnixFileStream.cpp - platform/unix/UnixPipe.cpp - ) - - if (NOT APPLE) - target_link_libraries(CruBase PUBLIC pthread) - endif() -endif() - -if (APPLE) - find_library(CORE_FOUNDATION CoreFoundation REQUIRED) - target_link_libraries(CruBase PUBLIC ${CORE_FOUNDATION}) - - target_sources(CruBase PRIVATE - platform/osx/Convert.cpp - platform/osx/Exception.cpp - ) -endif() - -if (EMSCRIPTEN) - target_compile_options(CruBase PUBLIC "-fwasm-exceptions") - target_link_options(CruBase PUBLIC "-fwasm-exceptions") - - target_sources(CruBase PRIVATE - platform/web/WebException.cpp - ) -endif() - -if (WIN32) - target_sources(CruBase PRIVATE - platform/win/BridgeComStream.cpp - platform/win/ComAutoInit.cpp - platform/win/DebugLogTarget.cpp - platform/win/Exception.cpp - platform/win/StreamConvert.cpp - platform/win/Win32FileStream.cpp - ) - - target_link_libraries(CruBase PUBLIC Shlwapi.lib) -endif() - -if (WIN32) - target_compile_definitions(CruBase PUBLIC CRU_PLATFORM_WINDOWS) -elseif(APPLE) - target_compile_definitions(CruBase PUBLIC CRU_PLATFORM_OSX) -elseif(EMSCRIPTEN) - target_compile_definitions(CruBase PUBLIC CRU_PLATFORM_EMSCRIPTEN) -else() - target_compile_definitions(CruBase PUBLIC CRU_PLATFORM_LINUX) -endif() - -target_link_libraries(CruBase PUBLIC double-conversion) diff --git a/src/common/Exception.cpp b/src/common/Exception.cpp deleted file mode 100644 index 4110ad56..00000000 --- a/src/common/Exception.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "cru/common/Exception.h" - -#include "cru/common/Format.h" - -#include - -namespace cru { -Exception::Exception(String message, std::unique_ptr inner) - : message_(std::move(message)), inner_(std::move(inner)) {} - -Exception::~Exception() {} - -const char* Exception::what() const noexcept { - if (!message_.empty() && utf8_message_.empty()) { - utf8_message_ = message_.ToUtf8(); - } - - return utf8_message_.c_str(); -} - -void Exception::AppendMessage(StringView additional_message) { - message_ += u" "; - message_ += additional_message; -} - -void Exception::AppendMessage(std::optional additional_message) { - if (additional_message) AppendMessage(*additional_message); -} - -ErrnoException::ErrnoException(String message) - : ErrnoException(message, errno) {} - -ErrnoException::ErrnoException(String message, int errno_code) - : Exception(Format(u"{}. Errno is {}.", message, errno_code)), - errno_code_(errno_code) {} -} // namespace cru diff --git a/src/common/Format.cpp b/src/common/Format.cpp deleted file mode 100644 index d58c90b7..00000000 --- a/src/common/Format.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "cru/common/Format.h" - -namespace cru { -namespace details { -FormatToken ParsePlaceHolder(String place_holder_string) { - if (place_holder_string.empty()) { - return FormatToken::NonePlaceHolder({}); - } - - if (place_holder_string.StartWith(u":")) { - if (place_holder_string.Find(u':', 1) != -1) { - throw Exception(u"Two ':' inside placeholder."); - } - - return FormatToken::NonePlaceHolder(place_holder_string.substr(1)); - } - if (IsDigit(place_holder_string[0])) { - int position = 0; - int index = 0; - while (index < place_holder_string.size() && - IsDigit(place_holder_string[index])) { - position = position * 10 + place_holder_string[index] - '0'; - index++; - } - - String option; - - if (index != place_holder_string.size()) { - if (place_holder_string[index] != ':') { - throw Exception(u"Invalid placeholder in format."); - } - - option = place_holder_string.substr(index + 1); - } - - return FormatToken::PositionedPlaceHolder(position, std::move(option)); - } - - auto separator_index = place_holder_string.Find(':'); - if (separator_index == -1) { - return FormatToken::NamedPlaceHolder(place_holder_string, {}); - } else { - return FormatToken::NamedPlaceHolder( - place_holder_string.substr(0, separator_index), - place_holder_string.substr(separator_index + 1)); - } -} - -std::vector ParseToFormatTokenList(StringView str) { - std::vector result; - - auto push_char = [&result](char16_t c) { - if (result.empty() || result.back().type == FormatTokenType::PlaceHolder) { - result.push_back(FormatToken::Text()); - } - result.back().data.append(c); - }; - - bool try_to_escape = false; - bool is_in_place_holder = false; - String place_holder_string; - - for (auto c : str) { - if (c == u'{') { - if (try_to_escape) { - push_char(u'{'); - try_to_escape = false; - is_in_place_holder = false; - } else { - if (is_in_place_holder) { - throw Exception(u"Invalid format string: '{' inside placeholder."); - } - - try_to_escape = true; - is_in_place_holder = true; - } - } else if (c == u'}') { - if (is_in_place_holder) { - is_in_place_holder = false; - result.push_back(ParsePlaceHolder(std::move(place_holder_string))); - place_holder_string.clear(); - } else { - push_char(u'}'); - } - try_to_escape = false; - } else { - if (is_in_place_holder) { - place_holder_string.push_back(c); - } else { - push_char(c); - } - try_to_escape = false; - } - } - return result; -} - -void FormatAppendFromFormatTokenList( - String& current, const std::vector& format_token_list, - Index index) { - for (Index i = index; i < static_cast(format_token_list.size()); i++) { - const auto& token = format_token_list[i]; - if (token.type == FormatTokenType::PlaceHolder) { - throw Exception(u"More placeholder than args."); - } else { - current += token.data; - } - } -} -} // namespace details -} // namespace cru diff --git a/src/common/PropertyTree.cpp b/src/common/PropertyTree.cpp deleted file mode 100644 index b587becb..00000000 --- a/src/common/PropertyTree.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "cru/common/PropertyTree.h" -#include -#include "cru/common/Exception.h" - -namespace cru { -String PropertySubTreeRef::CombineKey(StringView left, StringView right) { - return PropertyTree::CombineKey(left, right); -} - -PropertySubTreeRef::PropertySubTreeRef(PropertyTree* tree, String path) - : tree_(tree), path_(std::move(path)) { - Expects(tree); -} - -PropertySubTreeRef PropertySubTreeRef::GetParent() const { - for (Index i = path_.size() - 1; i >= 0; i--) { - if (path_[i] == '.') { - return PropertySubTreeRef(tree_, path_.substr(0, i)); - } - } - - return PropertySubTreeRef(tree_, {}); -} - -PropertySubTreeRef PropertySubTreeRef::GetChild(const String& key) const { - return PropertySubTreeRef(tree_, CombineKey(path_, key)); -} - -String PropertySubTreeRef::GetValue(const String& key) const { - return tree_->GetValue(CombineKey(path_, key)); -} - -void PropertySubTreeRef::SetValue(const String& key, String value) { - tree_->SetValue(CombineKey(path_, key), std::move(value)); -} - -void PropertySubTreeRef::DeleteValue(const String& key) { - tree_->DeleteValue(CombineKey(path_, key)); -} - -String PropertyTree::CombineKey(StringView left, StringView right) { - return String(left) + String(left.empty() ? u"" : u".") + String(right); -} - -PropertyTree::PropertyTree(std::unordered_map values) - : values_(std::move(values)) {} - -String PropertyTree::GetValue(const String& key) const { - auto it = values_.find(key); - if (it == values_.end()) { - throw Exception(u"Property tree has no value."); - } - return it->second; -} - -void PropertyTree::SetValue(const String& key, String value) { - values_[key] = std::move(value); -} - -void PropertyTree::DeleteValue(const String& key) { - auto it = values_.find(key); - if (it != values_.end()) { - values_.erase(it); - } -} - -PropertySubTreeRef PropertyTree::GetSubTreeRef(const String& path) { - return PropertySubTreeRef(this, path); -} - -} // namespace cru diff --git a/src/common/String.cpp b/src/common/String.cpp deleted file mode 100644 index 27712f01..00000000 --- a/src/common/String.cpp +++ /dev/null @@ -1,672 +0,0 @@ -#include "cru/common/String.h" - -#include "cru/common/Buffer.h" -#include "cru/common/Exception.h" -#include "cru/common/StringToNumberConverter.h" -#include "cru/common/StringUtil.h" - -#include -#include - -#include -#include -#include -#include -#include - -namespace cru { -template -Index GetStrSize(const C* str) { - Index i = 0; - while (str[i]) { - i++; - } - return i; -} - -String String::FromUtf8(const char* str) { - return FromUtf8(str, GetStrSize(str)); -} - -String String::FromUtf8(const char* str, Index size) { - String result; - Utf8CodePointIterator iter(str, size); - for (auto cp : iter) { - Utf16EncodeCodePointAppend( - cp, - std::bind(&String::push_back, std::ref(result), std::placeholders::_1)); - } - return result; -} - -String String::FromUtf8(const std::byte* str, Index size) { - return String::FromUtf8(reinterpret_cast(str), size); -} - -String String::FromUtf8(const Buffer& buffer) { - return String::FromUtf8(buffer.GetUsedBeginPtr(), buffer.GetUsedSize()); -} - -String String::FromStdPath(const std::filesystem::path& path) { - return String::FromUtf8(path.string()); -} - -char16_t String::kEmptyBuffer[1] = {0}; - -String::String(const_pointer str) : String(str, GetStrSize(str)) {} - -String::String(const_pointer str, Index size) { - this->buffer_ = new value_type[size + 1]; - std::memcpy(this->buffer_, str, size * sizeof(char16_t)); - this->buffer_[size] = 0; - this->size_ = size; - this->capacity_ = size; -} - -String::String(size_type size, value_type ch) : String() { - reserve(size); - for (Index i = 0; i < size; i++) { - append(ch); - } -} - -String::String(std::initializer_list l) - : String(l.begin(), l.size()) {} - -#ifdef CRU_PLATFORM_WINDOWS -String::String(const wchar_t* str) : String(str, GetStrSize(str)) {} -String::String(const wchar_t* str, Index size) - : String(reinterpret_cast(str), size) {} -#endif - -String::String(const String& other) { - if (other.size_ == 0) return; - this->buffer_ = new value_type[other.size_ + 1]; - std::memcpy(this->buffer_, other.buffer_, other.size_ * sizeof(value_type)); - this->buffer_[other.size_] = 0; - this->size_ = other.size_; - this->capacity_ = other.size_; -} - -String::String(String&& other) noexcept { - this->buffer_ = other.buffer_; - this->size_ = other.size_; - this->capacity_ = other.capacity_; - other.buffer_ = kEmptyBuffer; - other.size_ = 0; - other.capacity_ = 0; -} - -String& String::operator=(const String& other) { - if (this != &other) { - if (this->buffer_ != kEmptyBuffer) { - delete[] this->buffer_; - } - - if (other.buffer_ == kEmptyBuffer) { - this->buffer_ = kEmptyBuffer; - this->size_ = 0; - this->capacity_ = 0; - } else { - this->buffer_ = new value_type[other.size_ + 1]; - std::memcpy(this->buffer_, other.buffer_, - other.size_ * sizeof(value_type)); - this->buffer_[other.size_] = 0; - this->size_ = other.size_; - this->capacity_ = other.size_; - } - } - return *this; -} - -String& String::operator=(String&& other) noexcept { - if (this != &other) { - if (this->buffer_ != kEmptyBuffer) { - delete[] this->buffer_; - } - - this->buffer_ = other.buffer_; - this->size_ = other.size_; - this->capacity_ = other.capacity_; - other.buffer_ = kEmptyBuffer; - other.size_ = 0; - other.capacity_ = 0; - } - return *this; -} - -String::~String() { - if (this->buffer_ != kEmptyBuffer) { - delete[] this->buffer_; - } -} - -String::String(from_buffer_tag, pointer buffer, Index size, Index capacity) - : buffer_(buffer), size_(size), capacity_(capacity) {} - -void String::clear() { resize(0); } - -void String::resize(Index new_size) { - Expects(new_size >= 0); - - if (new_size == size_) return; - - if (new_size < size_) { - size_ = new_size; - buffer_[size_] = 0; - } else { - reserve(new_size); - std::memset(buffer_ + size_, 0, sizeof(value_type) * (new_size - size_)); - buffer_[new_size] = 0; - size_ = new_size; - } -} - -void String::shrink_to_fit() { - if (capacity_ == size_) return; - if (size_ == 0) { - delete[] buffer_; - buffer_ = kEmptyBuffer; - size_ = 0; - capacity_ = 0; - } else { - auto new_buffer = new value_type[size_ + 1]; - std::memcpy(new_buffer, buffer_, sizeof(value_type) * size_); - delete[] buffer_; - buffer_ = new_buffer; - capacity_ = size_; - } -} - -void String::reserve(Index new_capacity) { - Expects(new_capacity >= 0); - if (new_capacity <= this->capacity_) return; - if (new_capacity > 0) { - pointer new_buffer = new value_type[new_capacity + 1]; - if (this->buffer_ != kEmptyBuffer) { - memcpy(new_buffer, this->buffer_, this->size_ * sizeof(value_type)); - delete[] this->buffer_; - } - new_buffer[this->size_] = 0; - this->buffer_ = new_buffer; - this->capacity_ = new_capacity; - } -} - -String::iterator String::insert(const_iterator pos, const_iterator str, - Index size) { - Expects(pos >= cbegin() && pos <= cend()); - - std::vector backup_buffer; - if (str >= buffer_ && str < buffer_ + size_) { - backup_buffer.resize(size); - std::copy(str, str + size, backup_buffer.begin()); - str = backup_buffer.data(); - } - - Index index = pos - cbegin(); - - Index new_size = size_ + size; - if (new_size > capacity_) { - auto new_capacity = capacity_; - if (new_capacity == 0) { - new_capacity = new_size; - } else { - while (new_capacity < new_size) { - new_capacity *= 2; - } - } - - this->reserve(new_capacity); - } - - std::memmove(begin() + index + size, begin() + index, - (size_ - index) * sizeof(value_type)); - std::memcpy(begin() + index, str, size * sizeof(value_type)); - - buffer_[new_size] = 0; - size_ = new_size; - - return begin() + new_size; -} - -String::iterator String::erase(const_iterator start, const_iterator end) { - Expects(buffer_ <= start && start <= end && end <= buffer_ + size_); - - Index new_size = size_ - (end - start); - - auto s = const_cast(start); - auto e = const_cast(end); - - std::memmove(s, e, (cend() - end) * sizeof(value_type)); - this->size_ = new_size; - this->buffer_[new_size] = 0; - - return s; -} - -String& String::operator+=(StringView other) { - append(other); - return *this; -} - -StringView String::View() const { return *this; } - -Index String::Find(value_type value, Index start) const { - return View().Find(value, start); -} - -std::vector String::Split(value_type separator, - bool remove_space_line) const { - return View().Split(separator, remove_space_line); -} - -std::vector String::SplitToLines(bool remove_space_line) const { - return View().SplitToLines(remove_space_line); -} - -bool String::StartWith(StringView str) const { return View().StartWith(str); } - -bool String::EndWith(StringView str) const { return View().EndWith(str); } - -std::string String::ToUtf8() const { return View().ToUtf8(); } - -Buffer String::ToUtf8Buffer(bool end_zero) const { - return View().ToUtf8Buffer(); -} - -String& String::TrimStart() { - if (size_ == 0) return *this; - - auto start = begin(); - while (start != end() && IsWhitespace(*start)) { - ++start; - } - - if (start == end()) { - clear(); - } else { - erase(begin(), start); - } - - return *this; -} - -String& String::TrimEnd() { - if (size_ == 0) return *this; - while (size_ > 0 && IsWhitespace(buffer_[size_ - 1])) { - size_--; - } - - return *this; -} - -String& String::Trim() { - TrimStart(); - TrimEnd(); - return *this; -} - -void String::AppendCodePoint(CodePoint code_point) { - if (!Utf16EncodeCodePointAppend( - code_point, - std::bind(&String::push_back, this, std::placeholders::_1))) { - throw TextEncodeException(u"Code point out of range."); - } -} - -Index String::IndexFromCodeUnitToCodePoint(Index code_unit_index) const { - return View().IndexFromCodeUnitToCodePoint(code_unit_index); -} - -Index String::IndexFromCodePointToCodeUnit(Index code_point_index) const { - return View().IndexFromCodePointToCodeUnit(code_point_index); -} - -Range String::RangeFromCodeUnitToCodePoint(Range code_unit_range) const { - return View().RangeFromCodeUnitToCodePoint(code_unit_range); -} - -Range String::RangeFromCodePointToCodeUnit(Range code_point_range) const { - return View().RangeFromCodePointToCodeUnit(code_point_range); -} - -int String::ParseToInt(Index* processed_characters_count, - StringToNumberFlag flags, int base) const { - return View().ParseToInt(processed_characters_count, flags, base); -} - -long long String::ParseToLongLong(Index* processed_characters_count, - StringToNumberFlag flags, int base) const { - return View().ParseToLongLong(processed_characters_count, flags, base); -} - -float String::ParseToFloat(Index* processed_characters_count, - StringToNumberFlag flags) const { - return View().ParseToFloat(processed_characters_count, flags); -} - -double String::ParseToDouble(Index* processed_characters_count, - StringToNumberFlag flags) const { - return View().ParseToDouble(processed_characters_count, flags); -} - -std::vector String::ParseToFloatList(value_type separator) const { - return View().ParseToFloatList(separator); -} - -std::vector String::ParseToDoubleList(value_type separator) const { - return View().ParseToDoubleList(separator); -} - -std::ostream& operator<<(std::ostream& os, const String& value) { - os << value.ToUtf8(); - return os; -} - -namespace { -inline int Compare(char16_t left, char16_t right) { - if (left < right) return -1; - if (left > right) return 1; - return 0; -} - -inline int CaseInsensitiveCompare(char16_t left, char16_t right) { - return Compare(ToLower(left), ToLower(right)); -} -} // namespace - -int String::Compare(const String& other) const { return View().Compare(other); } -int String::CaseInsensitiveCompare(const String& other) const { - return View().CaseInsensitiveCompare(other); -} - -int StringView::Compare(const StringView& other) const { - const_iterator i1 = cbegin(); - const_iterator i2 = other.cbegin(); - - const_iterator end1 = cend(); - const_iterator end2 = other.cend(); - - while (i1 != end1 && i2 != end2) { - int r = cru::Compare(*i1, *i2); - if (r != 0) return r; - i1++; - i2++; - } - - if (i1 == end1) { - if (i2 == end2) { - return 0; - } else { - return -1; - } - } else { - return 1; - } -} - -int StringView::CaseInsensitiveCompare(const StringView& other) const { - const_iterator i1 = cbegin(); - const_iterator i2 = other.cbegin(); - - const_iterator end1 = cend(); - const_iterator end2 = other.cend(); - - while (i1 != end1 && i2 != end2) { - int r = cru::CaseInsensitiveCompare(*i1, *i2); - if (r != 0) return r; - i1++; - i2++; - } - - if (i1 == end1) { - if (i2 == end2) { - return 0; - } else { - return -1; - } - } else { - return 1; - } -} - -StringView StringView::substr(Index pos) { - Expects(pos >= 0 && pos < size_); - return StringView(ptr_ + pos, size_ - pos); -} - -StringView StringView::substr(Index pos, Index size) { - Expects(pos >= 0 && pos < size_); - - return StringView(ptr_ + pos, std::min(size, size_ - pos)); -} - -Index StringView::Find(value_type value, Index start) const { - Expects(start >= 0 && start <= size_); - - for (Index i = start; i < size_; ++i) { - if (ptr_[i] == value) return i; - } - return -1; -} - -std::vector StringView::Split(value_type separator, - bool remove_space_line) const { - std::vector result; - - if (size_ == 0) return result; - - Index line_start = 0; - Index line_end = 0; - while (line_end < size_) { - if (ptr_[line_end] == separator) { - if (remove_space_line) { - bool add = false; - for (Index i = line_start; i < line_end; i++) { - if (!IsWhitespace(ptr_[i])) { - add = true; - break; - } - } - if (add) result.emplace_back(begin() + line_start, begin() + line_end); - } else { - result.emplace_back(begin() + line_start, begin() + line_end); - } - line_start = line_end + 1; - line_end = line_start; - } else { - line_end++; - } - } - - if (remove_space_line) { - bool add = false; - for (Index i = line_start; i < size_; i++) { - if (!IsWhitespace(ptr_[i])) { - add = true; - break; - } - } - if (add) result.emplace_back(begin() + line_start, begin() + size_); - } else { - result.emplace_back(begin() + line_start, begin() + size_); - } - - return result; -} - -std::vector StringView::SplitToLines(bool remove_space_line) const { - return Split(u'\n', remove_space_line); -} - -bool StringView::StartWith(StringView str) const { - if (str.size() > size_) return false; - return std::memcmp(str.data(), ptr_, str.size()) == 0; -} - -bool StringView::EndWith(StringView str) const { - if (str.size() > size_) return false; - return std::memcmp(str.data(), ptr_ + size_ - str.size(), str.size()) == 0; -} - -Index StringView::IndexFromCodeUnitToCodePoint(Index code_unit_index) const { - auto iter = CodePointIterator(); - Index result = 0; - while (iter.GetPosition() < code_unit_index && !iter.IsPastEnd()) { - ++iter; - ++result; - } - return result; -} - -Index StringView::IndexFromCodePointToCodeUnit(Index code_point_index) const { - auto iter = CodePointIterator(); - Index cpi = 0; - while (cpi < code_point_index && !iter.IsPastEnd()) { - ++iter; - ++cpi; - } - return iter.GetPosition(); -} - -Range StringView::RangeFromCodeUnitToCodePoint(Range code_unit_range) const { - return Range::FromTwoSides( - IndexFromCodeUnitToCodePoint(code_unit_range.GetStart()), - IndexFromCodeUnitToCodePoint(code_unit_range.GetEnd())); -} - -Range StringView::RangeFromCodePointToCodeUnit(Range code_point_range) const { - return Range::FromTwoSides( - IndexFromCodePointToCodeUnit(code_point_range.GetStart()), - IndexFromCodePointToCodeUnit(code_point_range.GetEnd())); -} - -std::string StringView::ToUtf8() const { - std::string result; - for (auto cp : CodePointIterator()) { - Utf8EncodeCodePointAppend( - cp, std::bind(&std::string::push_back, std::ref(result), - std::placeholders::_1)); - } - return result; -} - -Buffer StringView::ToUtf8Buffer(bool end_zero) const { - const Index grow_step = 10; - Buffer buffer(grow_step); // Maybe another init value is more reasonable. - auto push_back = [&buffer](char c) { - if (buffer.IsUsedReachEnd()) { - buffer.ResizeBuffer(buffer.GetBufferSize() + grow_step, true); - } - buffer.PushBack(static_cast(c)); - }; - for (auto cp : CodePointIterator()) { - Utf8EncodeCodePointAppend(cp, push_back); - } - if (end_zero) { - push_back(0); - } - return buffer; -} - -int StringView::ParseToInt(Index* processed_characters_count, - StringToNumberFlag flags, int base) const { - return ParseToInteger(processed_characters_count, flags, base); -} - -long long StringView::ParseToLongLong(Index* processed_characters_count, - StringToNumberFlag flags, - int base) const { - return ParseToInteger(processed_characters_count, flags, base); -} - -static int MapStringToDoubleFlags(StringToNumberFlag flags) { - int f = double_conversion::StringToDoubleConverter::ALLOW_CASE_INSENSIBILITY; - if (flags & StringToNumberFlags::kAllowLeadingSpaces) { - f |= double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES; - } - if (flags & StringToNumberFlags::kAllowTrailingSpaces) { - f |= double_conversion::StringToDoubleConverter::ALLOW_TRAILING_SPACES; - } - if (flags & StringToNumberFlags::kAllowTrailingJunk) { - f |= double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK; - } - return f; -} - -static double_conversion::StringToDoubleConverter CreateStringToDoubleConverter( - StringToNumberFlag flags) { - return {MapStringToDoubleFlags(flags), 0.0, NAN, "inf", "nan"}; -} - -float StringView::ParseToFloat(Index* processed_characters_count, - StringToNumberFlag flags) const { - int pcc; - auto result = CreateStringToDoubleConverter(flags).StringToFloat( - reinterpret_cast(ptr_), static_cast(size_), &pcc); - if (processed_characters_count != nullptr) { - *processed_characters_count = pcc; - } - - if (flags & StringToNumberFlags::kThrowOnError && std::isnan(result)) { - throw Exception(u"Result of string to float conversion is NaN"); - } - - return result; -} - -double StringView::ParseToDouble(Index* processed_characters_count, - StringToNumberFlag flags) const { - int pcc; - auto result = CreateStringToDoubleConverter(flags).StringToDouble( - reinterpret_cast(ptr_), static_cast(size_), &pcc); - if (processed_characters_count != nullptr) { - *processed_characters_count = pcc; - } - - if (flags & StringToNumberFlags::kThrowOnError && std::isnan(result)) { - throw Exception(u"Result of string to double conversion is NaN"); - } - - return result; -} - -std::vector StringView::ParseToFloatList(value_type separator) const { - std::vector result; - auto list = Split(separator, true); - for (auto& item : list) { - auto value = item.ParseToFloat(); - if (std::isnan(value)) { - throw Exception(u"Invalid double value."); - } - result.push_back(value); - } - return result; -} - -std::vector StringView::ParseToDoubleList(value_type separator) const { - std::vector result; - auto list = Split(separator, true); - for (auto& item : list) { - auto value = item.ParseToDouble(); - if (std::isnan(value)) { - throw Exception(u"Invalid double value."); - } - result.push_back(value); - } - return result; -} - -String ToLower(StringView s) { - String result; - for (auto c : s) result.push_back(ToLower(c)); - return result; -} - -String ToUpper(StringView s) { - String result; - for (auto c : s) result.push_back(ToUpper(c)); - return result; -} -} // namespace cru diff --git a/src/common/StringToNumberConverter.cpp b/src/common/StringToNumberConverter.cpp deleted file mode 100644 index 7a926d3d..00000000 --- a/src/common/StringToNumberConverter.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include "cru/common/StringToNumberConverter.h" -#include "cru/common/Exception.h" - -namespace cru { -bool StringToIntegerConverter::CheckParams() const { - return base == 0 || base >= 2 & base <= 36; -} - -static bool IsSpace(char c) { - return c == ' ' || c == '\t' || c == '\n' || c == '\r'; -} - -StringToIntegerResult StringToIntegerConverter::Parse( - const char* const str, const Index size, - Index* processed_characters_count) const { - if (str == nullptr) throw std::invalid_argument("Invalid str."); - if (size < 0) throw std::invalid_argument("Invalid size."); - if (!CheckParams()) throw std::invalid_argument("Invalid parsing flags."); - - const bool throw_on_error = flags.Has(StringToNumberFlags::kThrowOnError); - - auto const end = str + size; - - auto current = str; - - if (flags & StringToNumberFlags::kAllowLeadingSpaces) { - while (current != end && IsSpace(*current)) { - current++; - } - } - - if (current == end) { - if (processed_characters_count) { - *processed_characters_count = 0; - } - if (throw_on_error) { - throw Exception(u"Empty string (after reading leading spaces)."); - } else { - return {false, 0}; - } - } - - bool negate = false; - - if (*current == '-') { - ++current; - negate = true; - } else if (*current == '+') { - ++current; - } - - if (current == end) { - if (processed_characters_count) { - *processed_characters_count = 0; - } - if (throw_on_error) { - throw Exception(u"Empty string (after reading sign)."); - } else { - return {false, 0}; - } - } - - int real_base = base; - - if (real_base == 0) { - if (*current == '0') { - ++current; - if (current == end) { - if (processed_characters_count) { - *processed_characters_count = current - str; - } - return {negate, 0}; - } else if (*current == 'x' || *current == 'X') { - ++current; - real_base = 16; - } else if (*current == 'b' || *current == 'B') { - ++current; - real_base = 2; - } else { - real_base = 8; - } - } else { - real_base = 10; - } - } - - if (current == end) { - if (processed_characters_count) { - *processed_characters_count = 0; - } - if (throw_on_error) { - throw Exception(u"Empty string (after reading head base indicator)."); - } else { - return {false, 0}; - } - } - - const bool allow_leading_zero = - flags.Has(StringToNumberFlags::kAllowLeadingZeroForInteger); - - while (current != end && *current == '0') { - current++; - } - - if (current == end) { - if (processed_characters_count) { - *processed_characters_count = current - str; - } - return {negate, 0}; - } - - const bool allow_trailing_junk = - flags.Has(StringToNumberFlags::kAllowTrailingJunk); - const bool allow_trailing_spaces = - flags.Has(StringToNumberFlags::kAllowTrailingSpaces); - - unsigned long long result = 0; - - while (current != end) { - const char c = *current; - if (c >= '0' && c <= (real_base > 10 ? '9' : real_base + '0' - 1)) { - result = result * real_base + c - '0'; - current++; - } else if (real_base > 10 && c >= 'a' && c <= (real_base + 'a' - 10 - 1)) { - result = result * real_base + c - 'a' + 10; - current++; - } else if (real_base > 10 && c >= 'A' && c <= (real_base + 'A' - 10 - 1)) { - result = result * real_base + c - 'A' + 10; - current++; - } else if (allow_trailing_junk) { - break; - } else if (allow_trailing_spaces && IsSpace(c)) { - break; - } else { - if (processed_characters_count) { - *processed_characters_count = 0; - } - if (throw_on_error) { - throw Exception(String(u"Read invalid character '") + c + u"'."); - } else { - return {false, 0}; - } - } - } - - if (allow_trailing_spaces) { - while (current != end && IsSpace(*current)) { - current++; - } - - if (current != end) { - if (processed_characters_count) { - *processed_characters_count = 0; - } - if (throw_on_error) { - throw Exception(u"There is trailing junk."); - } else { - return {false, 0}; - } - } - } - - if (processed_characters_count) { - *processed_characters_count = current - str; - } - - return {negate, result}; -} - -} // namespace cru diff --git a/src/common/StringUtil.cpp b/src/common/StringUtil.cpp deleted file mode 100644 index f584fd4e..00000000 --- a/src/common/StringUtil.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include "cru/common/StringUtil.h" -#include "cru/common/Base.h" -#include "cru/common/Exception.h" - -namespace cru { -using details::ExtractBits; - -CodePoint Utf8NextCodePoint(const char* ptr, Index size, Index current, - Index* next_position) { - CodePoint result; - - if (current >= size) { - result = k_invalid_code_point; - } else { - const auto cu0 = static_cast(ptr[current++]); - - auto read_next_folowing_code = [ptr, size, ¤t]() -> CodePoint { - if (current == size) - throw TextEncodeException( - u"Unexpected end when read continuing byte of multi-byte code " - "point."); - - const auto u = static_cast(ptr[current]); - if (!(u & (1u << 7)) || (u & (1u << 6))) { - throw TextEncodeException( - u"Unexpected bad-format (not 0b10xxxxxx) continuing byte of " - "multi-byte code point."); - } - - return ExtractBits(ptr[current++]); - }; - - if ((1u << 7) & cu0) { - if ((1u << 6) & cu0) { // 2~4-length code point - if ((1u << 5) & cu0) { // 3~4-length code point - if ((1u << 4) & cu0) { // 4-length code point - if (cu0 & (1u << 3)) { - throw TextEncodeException( - u"Unexpected bad-format begin byte (not 0b11110xxx) of 4-byte" - "code point."); - } - - const CodePoint s0 = ExtractBits(cu0) - << (6 * 3); - const CodePoint s1 = read_next_folowing_code() << (6 * 2); - const CodePoint s2 = read_next_folowing_code() << 6; - const CodePoint s3 = read_next_folowing_code(); - result = s0 + s1 + s2 + s3; - } else { // 3-length code point - const CodePoint s0 = ExtractBits(cu0) - << (6 * 2); - const CodePoint s1 = read_next_folowing_code() << 6; - const CodePoint s2 = read_next_folowing_code(); - result = s0 + s1 + s2; - } - } else { // 2-length code point - const CodePoint s0 = ExtractBits(cu0) - << 6; - const CodePoint s1 = read_next_folowing_code(); - result = s0 + s1; - } - } else { - throw TextEncodeException( - u"Unexpected bad-format (0b10xxxxxx) begin byte of a code point."); - } - } else { - result = static_cast(cu0); - } - } - - if (next_position != nullptr) *next_position = current; - return result; -} - -CodePoint Utf16NextCodePoint(const char16_t* ptr, Index size, Index current, - Index* next_position) { - CodePoint result; - - if (current >= size) { - result = k_invalid_code_point; - } else { - const auto cu0 = ptr[current++]; - - if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point - result = static_cast(cu0); - } else if (IsUtf16SurrogatePairLeading(cu0)) { // 2-length code point - if (current >= size) { - throw TextEncodeException( - u"Unexpected end when reading second code unit of surrogate pair."); - } - const auto cu1 = ptr[current++]; - - if (!IsUtf16SurrogatePairTrailing(cu1)) { - throw TextEncodeException( - u"Unexpected bad-range second code unit of surrogate pair."); - } - - const auto s0 = ExtractBits(cu0) << 10; - const auto s1 = ExtractBits(cu1); - - result = s0 + s1 + 0x10000; - - } else { - throw TextEncodeException( - u"Unexpected bad-range first code unit of surrogate pair."); - } - } - - if (next_position != nullptr) *next_position = current; - return result; -} - -CodePoint Utf16PreviousCodePoint(const char16_t* ptr, Index size, Index current, - Index* previous_position) { - CRU_UNUSED(size) - - CodePoint result; - if (current <= 0) { - result = k_invalid_code_point; - } else { - const auto cu0 = ptr[--current]; - - if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point - result = static_cast(cu0); - } else if (IsUtf16SurrogatePairTrailing(cu0)) { // 2-length code point - if (current <= 0) { - throw TextEncodeException( - u"Unexpected end when reading first code unit of surrogate pair."); - } - const auto cu1 = ptr[--current]; - - if (!IsUtf16SurrogatePairLeading(cu1)) { - throw TextEncodeException( - u"Unexpected bad-range first code unit of surrogate pair."); - } - - const auto s0 = ExtractBits(cu1) << 10; - const auto s1 = ExtractBits(cu0); - - result = s0 + s1 + 0x10000; - - } else { - throw TextEncodeException( - u"Unexpected bad-range second code unit of surrogate pair."); - } - } - - if (previous_position != nullptr) *previous_position = current; - return result; -} - -bool Utf16IsValidInsertPosition(const char16_t* ptr, Index size, - Index position) { - if (position < 0) return false; - if (position > size) return false; - if (position == 0) return true; - if (position == size) return true; - return !IsUtf16SurrogatePairTrailing(ptr[position]); -} - -Index Utf16BackwardUntil(const char16_t* ptr, Index size, Index position, - const std::function& predicate) { - if (position <= 0) return position; - while (true) { - Index p = position; - auto c = Utf16PreviousCodePoint(ptr, size, p, &position); - if (predicate(c)) return p; - if (c == k_invalid_code_point) return p; - } - UnreachableCode(); -} - -Index Utf16ForwardUntil(const char16_t* ptr, Index size, Index position, - const std::function& predicate) { - if (position >= size) return position; - while (true) { - Index p = position; - auto c = Utf16NextCodePoint(ptr, size, p, &position); - if (predicate(c)) return p; - if (c == k_invalid_code_point) return p; - } - UnreachableCode(); -} - -inline bool IsSpace(CodePoint c) { return c == 0x20 || c == 0xA; } - -Index Utf16PreviousWord(const char16_t* ptr, Index size, Index position, - bool* is_space) { - if (position <= 0) return position; - auto c = Utf16PreviousCodePoint(ptr, size, position, nullptr); - if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). - if (is_space) *is_space = true; - return Utf16BackwardUntil(ptr, size, position, - [](CodePoint c) { return !IsSpace(c); }); - } else { - if (is_space) *is_space = false; - return Utf16BackwardUntil(ptr, size, position, IsSpace); - } -} - -Index Utf16NextWord(const char16_t* ptr, Index size, Index position, - bool* is_space) { - if (position >= size) return position; - auto c = Utf16NextCodePoint(ptr, size, position, nullptr); - if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). - if (is_space) *is_space = true; - return Utf16ForwardUntil(ptr, size, position, - [](CodePoint c) { return !IsSpace(c); }); - } else { - if (is_space) *is_space = false; - return Utf16ForwardUntil(ptr, size, position, IsSpace); - } -} - -char16_t ToLower(char16_t c) { - if (c >= u'A' && c <= u'Z') { - return c - u'A' + u'a'; - } - return c; -} - -char16_t ToUpper(char16_t c) { - if (c >= u'a' && c <= u'z') { - return c - u'a' + u'A'; - } - return c; -} - -bool IsWhitespace(char16_t c) { - return c == u' ' || c == u'\t' || c == u'\n' || c == u'\r'; -} - -bool IsDigit(char16_t c) { return c >= u'0' && c <= u'9'; } - -Utf8CodePointIterator CreateUtf8Iterator(const std::byte* buffer, Index size) { - return Utf8CodePointIterator(reinterpret_cast(buffer), size); -} - -Utf8CodePointIterator CreateUtf8Iterator(const std::vector& buffer) { - return CreateUtf8Iterator(buffer.data(), buffer.size()); -} - -} // namespace cru diff --git a/src/common/SubProcess.cpp b/src/common/SubProcess.cpp deleted file mode 100644 index 33926f39..00000000 --- a/src/common/SubProcess.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "cru/common/SubProcess.h" - -#include - -#ifdef CRU_PLATFORM_UNIX -#include "cru/common/platform/unix/PosixSpawnSubProcess.h" -#endif - -namespace cru { - -#ifdef CRU_PLATFORM_UNIX -using ThisPlatformSubProcessImpl = platform::unix::PosixSpawnSubProcessImpl; -#endif - -PlatformSubProcess::PlatformSubProcess( - SubProcessStartInfo start_info, - std::shared_ptr impl) - : state_(new State(std::move(start_info), std::move(impl))), - lock_(state_->mutex, std::defer_lock) {} - -PlatformSubProcess::~PlatformSubProcess() {} - -void PlatformSubProcess::Start() { - std::lock_guard lock_guard(this->lock_); - - if (this->state_->status != SubProcessStatus::Prepare) { - throw SubProcessException(u"The process has already tried to start."); - } - - try { - this->state_->impl->PlatformCreateProcess(this->state_->start_info); - this->state_->status = SubProcessStatus::Running; - - auto thread = std::thread([state = state_] { - std::unique_lock lock(state->mutex); - state->exit_result = state->impl->PlatformWaitForProcess(); - state->status = SubProcessStatus::Exited; - state->condition_variable.notify_all(); - }); - - thread.detach(); - } catch (const std::exception& e) { - this->state_->status = SubProcessStatus::FailedToStart; - throw SubProcessFailedToStartException(u"Sub-process failed to start. " + - String::FromUtf8(e.what())); - } -} - -void PlatformSubProcess::Wait( - std::optional wait_time) { - std::lock_guard lock_guard(this->lock_); - - if (this->state_->status == SubProcessStatus::Prepare) { - throw SubProcessException( - u"The process does not start. Can't wait for it."); - } - - if (this->state_->status == SubProcessStatus::FailedToStart) { - throw SubProcessException( - u"The process failed to start. Can't wait for it."); - } - - if (this->state_->status == SubProcessStatus::Exited) { - return; - } - - auto predicate = [this] { - return this->state_->status == SubProcessStatus::Exited; - }; - - if (wait_time) { - this->state_->condition_variable.wait_for(this->lock_, *wait_time, - predicate); - } else { - this->state_->condition_variable.wait(this->lock_, predicate); - } -} - -void PlatformSubProcess::Kill() { - std::lock_guard lock_guard(this->lock_); - - if (this->state_->status == SubProcessStatus::Prepare) { - throw SubProcessException(u"The process does not start. Can't kill it."); - } - - if (this->state_->status == SubProcessStatus::FailedToStart) { - throw SubProcessException(u"The process failed to start. Can't kill it."); - } - - if (this->state_->status == SubProcessStatus::Exited) { - return; - } - - if (this->state_->killed) { - return; - } - - this->state_->impl->PlatformKillProcess(); - this->state_->killed = true; -} - -SubProcessStatus PlatformSubProcess::GetStatus() { - std::lock_guard lock_guard(this->lock_); - return this->state_->status; -} - -SubProcessExitResult PlatformSubProcess::GetExitResult() { - std::lock_guard lock_guard(this->lock_); - - if (this->state_->status == SubProcessStatus::Prepare) { - throw SubProcessException( - u"The process does not start. Can't get exit result."); - } - - if (this->state_->status == SubProcessStatus::FailedToStart) { - throw SubProcessException( - u"The process failed to start. Can't get exit result."); - } - - if (this->state_->status == SubProcessStatus::Running) { - throw SubProcessException( - u"The process is running. Can't get exit result."); - } - - return this->state_->exit_result; -} - -io::Stream* PlatformSubProcess::GetStdinStream() { - return this->state_->impl->GetStdinStream(); -} - -io::Stream* PlatformSubProcess::GetStdoutStream() { - return this->state_->impl->GetStdoutStream(); -} - -io::Stream* PlatformSubProcess::GetStderrStream() { - return this->state_->impl->GetStderrStream(); -} - -SubProcess SubProcess::Create(String program, std::vector arguments, - std::unordered_map environments) { - SubProcessStartInfo start_info; - start_info.program = std::move(program); - start_info.arguments = std::move(arguments); - start_info.environments = std::move(environments); - return SubProcess(std::move(start_info)); -} - -SubProcessExitResult SubProcess::Call( - String program, std::vector arguments, - std::unordered_map environments) { - auto process = - Create(std::move(program), std::move(arguments), std::move(environments)); - process.Wait(); - return process.GetExitResult(); -} - -SubProcess::SubProcess(SubProcessStartInfo start_info) { - platform_process_.reset(new PlatformSubProcess( - std::move(start_info), std::make_shared())); - platform_process_->Start(); -} - -SubProcess::~SubProcess() {} - -void SubProcess::Wait(std::optional wait_time) { - CheckValid(); - platform_process_->Wait(wait_time); -} - -void SubProcess::Kill() { - CheckValid(); - platform_process_->Kill(); -} - -SubProcessStatus SubProcess::GetStatus() { - CheckValid(); - return platform_process_->GetStatus(); -} - -SubProcessExitResult SubProcess::GetExitResult() { - CheckValid(); - return platform_process_->GetExitResult(); -} - -io::Stream* SubProcess::GetStdinStream() { - CheckValid(); - return platform_process_->GetStdinStream(); -} - -io::Stream* SubProcess::GetStdoutStream() { - CheckValid(); - return platform_process_->GetStdoutStream(); -} - -io::Stream* SubProcess::GetStderrStream() { - CheckValid(); - return platform_process_->GetStderrStream(); -} - -void SubProcess::Detach() { auto p = platform_process_.release(); } - -void SubProcess::CheckValid() const { - if (!IsValid()) { - throw SubProcessException(u"SubProcess instance is invalid."); - } -} - -} // namespace cru diff --git a/src/common/io/AutoReadStream.cpp b/src/common/io/AutoReadStream.cpp deleted file mode 100644 index 18bc18da..00000000 --- a/src/common/io/AutoReadStream.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "cru/common/io/AutoReadStream.h" -#include "cru/common/io/Stream.h" - -#include - -namespace cru::io { - -AutoReadStream::AutoReadStream(Stream* stream, bool auto_delete, - const AutoReadStreamOptions& options) - : Stream(false, true, stream->CanSeek()) { - auto buffer_stream_options = options.GetBufferStreamOptions(); - stream_ = stream; - size_per_read_ = buffer_stream_options.GetBlockSizeOrDefault(); - buffer_stream_ = std::make_unique(buffer_stream_options); - background_thread_ = std::thread(&AutoReadStream::BackgroundThreadRun, this); -} - -AutoReadStream::~AutoReadStream() { - if (auto_delete_) { - delete stream_; - } -} - -Index AutoReadStream::DoRead(std::byte* buffer, Index offset, Index size) { - std::unique_lock lock(buffer_stream_mutex_); - return buffer_stream_->Read(buffer, offset, size); -} - -Index AutoReadStream::DoWrite(const std::byte* buffer, Index offset, - Index size) { - return stream_->Write(buffer, offset, size); -} - -void AutoReadStream::DoFlush() { stream_->Flush(); } - -void AutoReadStream::DoClose() {} - -void AutoReadStream::BackgroundThreadRun() { - std::vector buffer(size_per_read_); - while (true) { - try { - auto read = stream_->Read(buffer.data(), buffer.size()); - if (read == 0) { - buffer_stream_->SetEof(); - break; - } else { - buffer_stream_->Write(buffer.data(), read); - } - } catch (const StreamAlreadyClosedException& exception) { - buffer_stream_->SetEof(); - break; - } - } -} - -} // namespace cru::io diff --git a/src/common/io/BufferStream.cpp b/src/common/io/BufferStream.cpp deleted file mode 100644 index 73e5719b..00000000 --- a/src/common/io/BufferStream.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "cru/common/io/BufferStream.h" -#include "cru/common/io/Stream.h" - -namespace cru::io { -BufferStream::BufferStream(const BufferStreamOptions& options) - : Stream(false, true, true) { - block_size_ = options.GetBlockSizeOrDefault(); - max_block_count_ = options.GetMaxBlockCount(); - - eof_ = false; -} - -BufferStream::~BufferStream() { DoClose(); } - -Index BufferStream::DoRead(std::byte* buffer, Index offset, Index size) { - std::unique_lock lock(mutex_); - - condition_variable_.wait(lock, - [this] { return !buffer_list_.empty() || eof_; }); - - if (buffer_list_.empty() && eof_) { - return 0; - } - - auto full = max_block_count_ > 0 && buffer_list_.size() == max_block_count_; - - Index read = 0; - - while (!buffer_list_.empty()) { - auto& stream_buffer = buffer_list_.front(); - auto this_read = - stream_buffer.PopFront(buffer + offset + read, size - read); - if (stream_buffer.GetUsedSize() == 0) { - buffer_list_.pop_front(); - } - read += this_read; - if (read == size) { - break; - } - } - - if (full && buffer_list_.size() < max_block_count_) { - // By convention, there should be at most one producer waiting. So - // notify_one and notify_all should be the same. - condition_variable_.notify_one(); - } - - return read; -} - -Index BufferStream::DoWrite(const std::byte* buffer, Index offset, Index size) { - std::unique_lock lock(mutex_); - - if (eof_) { - throw WriteAfterEofException( - u"Stream has been set eof. Can't write to it any more."); - } - - condition_variable_.wait(lock, [this] { - return max_block_count_ <= 0 || buffer_list_.size() < max_block_count_ || - buffer_list_.back().GetBackFree() > 0; - }); - - auto empty = buffer_list_.empty(); - - Index written = 0; - - if (empty) { - buffer_list_.push_back(Buffer(block_size_)); - } - - while (true) { - if (buffer_list_.back().GetBackFree() == 0) { - if (max_block_count_ > 0 && buffer_list_.size() == max_block_count_) { - break; - } - buffer_list_.push_back(Buffer(block_size_)); - } - auto& stream_buffer = buffer_list_.back(); - auto this_written = - stream_buffer.PushBack(buffer + offset + written, size - written); - written += this_written; - if (written == size) { - break; - } - } - - if (empty) { - // By convention, there should be at most one consumer waiting. So - // notify_one and notify_all should be the same. - condition_variable_.notify_one(); - } - - return written; -} - -void BufferStream::SetEof() { - std::unique_lock lock(mutex_); - - eof_ = true; - if (buffer_list_.empty()) { - // By convention, there should be at most one consumer waiting. So - // notify_one and notify_all should be the same. - condition_variable_.notify_one(); - } -} - -void BufferStream::DoClose() { CRU_STREAM_BEGIN_CLOSE } -} // namespace cru::io diff --git a/src/common/io/CFileStream.cpp b/src/common/io/CFileStream.cpp deleted file mode 100644 index 01456437..00000000 --- a/src/common/io/CFileStream.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "cru/common/io/CFileStream.h" -#include "cru/common/Exception.h" -#include "cru/common/io/Stream.h" - -#include - -namespace cru::io { -static bool ModeCanRead(const char* mode) { - for (const char* p = mode; *p != '\0'; p++) { - if (*p == 'r' || *p == '+') { - return true; - } - } - return false; -} - -static bool ModeCanWrite(const char* mode) { - for (const char* p = mode; *p != '\0'; p++) { - if (*p == 'w' || *p == 'a' || *p == '+') { - return true; - } - } - return false; -} - -CFileStream::CFileStream(const char* path, const char* mode) - : Stream(true, ModeCanRead(mode), ModeCanWrite(mode)), - file_(std::fopen(path, mode)), - auto_close_(true) { - if (file_ == nullptr) { - throw ErrnoException(u"Cannot open file."); - } -} - -CFileStream::CFileStream(std::FILE* file, bool readable, bool writable, - bool auto_close) - : Stream(true, readable, writable), file_(file), auto_close_(auto_close) { - if (file_ == nullptr) { - throw Exception(u"File is NULL."); - } -} - -CFileStream::~CFileStream() { - if (auto_close_ && file_ != nullptr) { - std::fclose(file_); - } -} - -static int ConvertOriginFlag(Stream::SeekOrigin origin) { - switch (origin) { - case Stream::SeekOrigin::Begin: - return SEEK_SET; - case Stream::SeekOrigin::Current: - return SEEK_CUR; - case Stream::SeekOrigin::End: - return SEEK_END; - default: - throw Exception(u"Unknown seek origin."); - } -} - -Index CFileStream::DoSeek(Index offset, SeekOrigin origin) { - if (std::fseek(file_, offset, ConvertOriginFlag(origin))) { - throw ErrnoException(u"Seek failed."); - } - return DoTell(); -} - -Index CFileStream::DoTell() { - long position = std::ftell(file_); - if (position == -1) { - throw ErrnoException(u"Tell failed."); - } - return position; -} - -void CFileStream::DoRewind() { std::rewind(file_); } - -Index CFileStream::DoRead(std::byte* buffer, Index offset, Index size) { - auto count = std::fread(buffer + offset, 1, size, file_); - return count; -} - -Index CFileStream::DoWrite(const std::byte* buffer, Index offset, Index size) { - auto count = std::fwrite(buffer + offset, 1, size, file_); - return count; -} - -void CFileStream::DoFlush() { std::fflush(file_); } - -void CFileStream::DoClose() { - CRU_STREAM_BEGIN_CLOSE - std::fclose(file_); - file_ = nullptr; -} -} // namespace cru::io diff --git a/src/common/io/MemoryStream.cpp b/src/common/io/MemoryStream.cpp deleted file mode 100644 index 4b33d780..00000000 --- a/src/common/io/MemoryStream.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "cru/common/io/MemoryStream.h" - -#include -#include "cru/common/Exception.h" -#include "cru/common/io/Stream.h" - -namespace cru::io { -MemoryStream::MemoryStream( - std::byte* buffer, Index size, bool read_only, - std::function release_func) - : Stream(true, true, !read_only), - buffer_(buffer), - size_(size), - position_(0), - release_func_(std::move(release_func)) { - if (!buffer) { - throw Exception(u"Buffer is nullptr"); - } - if (size <= 0) { - throw Exception(u"Size is 0 or negative."); - } -} - -MemoryStream::~MemoryStream() {} - -void MemoryStream::Close() { DoClose(); } - -Index MemoryStream::DoSeek(Index offset, SeekOrigin origin) { - switch (origin) { - case SeekOrigin::Current: - position_ += offset; - break; - case SeekOrigin::Begin: - position_ = offset; - break; - case SeekOrigin::End: - position_ = size_ + offset; - break; - } - return position_; -} - -Index MemoryStream::DoRead(std::byte* buffer, Index offset, Index size) { - if (position_ + size > size_) { - size = size_ - position_; - } - if (size <= 0) { - return 0; - } - std::memmove(buffer + offset, buffer_ + position_, size); - position_ += size; - return size; -} - -Index MemoryStream::DoWrite(const std::byte* buffer, Index offset, Index size) { - if (position_ + size > size_) { - size = size_ - position_; - } - if (size <= 0) { - return 0; - } - std::memmove(buffer_ + position_, buffer + offset, size); - position_ += size; - return size; -} - -void MemoryStream::DoClose() { - CRU_STREAM_BEGIN_CLOSE - release_func_(buffer_, size_); - buffer_ = nullptr; - release_func_ = {}; -} - -} // namespace cru::io diff --git a/src/common/io/OpenFileFlag.cpp b/src/common/io/OpenFileFlag.cpp deleted file mode 100644 index 6b9957fe..00000000 --- a/src/common/io/OpenFileFlag.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "cru/common/io/OpenFileFlag.h" - -namespace cru::io { -bool CheckOpenFileFlag(OpenFileFlag flags) { - auto has = [flags](OpenFileFlag flag) { return flags & flag; }; - - if ((has(OpenFileFlags::Append) || has(OpenFileFlags::Truncate) || - has(OpenFileFlags::Create)) && - !has(OpenFileFlags::Write)) { - return false; - } - - if (has(OpenFileFlags::Truncate) && has(OpenFileFlags::Append)) { - return false; - } - - return true; -} -} // namespace cru::io diff --git a/src/common/io/ProxyStream.cpp b/src/common/io/ProxyStream.cpp deleted file mode 100644 index c2e64056..00000000 --- a/src/common/io/ProxyStream.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "cru/common/io/ProxyStream.h" -#include "cru/common/io/Stream.h" - -namespace cru::io { -ProxyStream::ProxyStream(ProxyStreamHandlers handlers) - : Stream(static_cast(handlers.seek), static_cast(handlers.read), - static_cast(handlers.write)), - handlers_(std::move(handlers)) {} - -ProxyStream::~ProxyStream() { DoClose(); } - -Index ProxyStream::DoSeek(Index offset, SeekOrigin origin) { - return handlers_.seek(offset, origin); -} - -Index ProxyStream::DoRead(std::byte* buffer, Index offset, Index size) { - return handlers_.read(buffer, offset, size); -} - -Index ProxyStream::DoWrite(const std::byte* buffer, Index offset, Index size) { - return handlers_.write(buffer, offset, size); -} - -void ProxyStream::DoFlush() { - if (handlers_.flush) { - handlers_.flush(); - } -} - -void ProxyStream::DoClose() { - CRU_STREAM_BEGIN_CLOSE - if (handlers_.close) { - handlers_.close(); - } - handlers_ = {}; -} -} // namespace cru::io diff --git a/src/common/io/Resource.cpp b/src/common/io/Resource.cpp deleted file mode 100644 index b847e1cf..00000000 --- a/src/common/io/Resource.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "cru/common/io/Resource.h" -#include "cru/common/Exception.h" -#include "cru/common/log/Logger.h" - -#if defined(CRU_PLATFORM_OSX) -#include -#elif defined(CRU_PLATFORM_WINDOWS) -#include -#endif - -#include - -namespace cru::io { -std::filesystem::path GetResourceDir() { - constexpr auto kLogTag = u"GetResourceDir"; - -#if defined(CRU_PLATFORM_OSX) - CFBundleRef main_bundle = CFBundleGetMainBundle(); - CFURLRef bundle_url = CFBundleCopyBundleURL(main_bundle); - CFStringRef cf_string_ref = - CFURLCopyFileSystemPath(bundle_url, kCFURLPOSIXPathStyle); - std::filesystem::path bundle_path( - CFStringGetCStringPtr(cf_string_ref, kCFStringEncodingUTF8)); - - CFRelease(bundle_url); - CFRelease(cf_string_ref); - - return bundle_path / "Contents/Resources"; -#elif defined(CRU_PLATFORM_WINDOWS) - wchar_t buffer[MAX_PATH]; - DWORD size = ::GetModuleFileNameW(nullptr, buffer, MAX_PATH); - std::filesystem::path module_path(buffer, buffer + size); - auto p = module_path; - while (p.has_parent_path()) { - p = p.parent_path(); - auto resource_dir_path = p / "assets"; - if (std::filesystem::exists(resource_dir_path) && - std::filesystem::is_directory(resource_dir_path)) { - return resource_dir_path; - } - } - - throw Exception(u"Failed to find resource directory."); -#else - throw Exception(u"Not implemented."); -#endif -} -} // namespace cru::io diff --git a/src/common/io/Stream.cpp b/src/common/io/Stream.cpp deleted file mode 100644 index 6b0a513c..00000000 --- a/src/common/io/Stream.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "cru/common/io/Stream.h" -#include "cru/common/Exception.h" -#include "cru/common/Format.h" - -#include - -namespace cru::io { -StreamOperationNotSupportedException::StreamOperationNotSupportedException( - String operation) - : operation_(std::move(operation)) { - SetMessage(Format(u"Stream operation {} not supported.", operation_)); -} - -void StreamOperationNotSupportedException::CheckSeek(bool seekable) { - if (!seekable) throw StreamOperationNotSupportedException(u"seek"); -} - -void StreamOperationNotSupportedException::CheckRead(bool readable) { - if (!readable) throw StreamOperationNotSupportedException(u"read"); -} - -void StreamOperationNotSupportedException::CheckWrite(bool writable) { - if (!writable) throw StreamOperationNotSupportedException(u"write"); -} - -StreamAlreadyClosedException::StreamAlreadyClosedException() - : Exception(u"Stream is already closed.") {} - -void StreamAlreadyClosedException::Check(bool closed) { - if (closed) throw StreamAlreadyClosedException(); -} - -Stream::Stream(SupportedOperations supported_operations) - : supported_operations_(std::move(supported_operations)), closed_(false) {} - -Stream::Stream(std::optional can_seek, std::optional can_read, - std::optional can_write) - : Stream(SupportedOperations{can_seek, can_read, can_write}) {} - -bool Stream::CanSeek() { - CheckClosed(); - return DoCanSeek(); -} - -Index Stream::Seek(Index offset, SeekOrigin origin) { - CheckClosed(); - StreamOperationNotSupportedException::CheckSeek(DoCanSeek()); - return DoSeek(offset, origin); -} - -Index Stream::Tell() { - CheckClosed(); - return DoTell(); -} - -void Stream::Rewind() { - CheckClosed(); - return DoRewind(); -} - -Index Stream::GetSize() { - CheckClosed(); - return DoGetSize(); -} - -bool Stream::CanRead() { - CheckClosed(); - return DoCanRead(); -} - -Index Stream::Read(std::byte* buffer, Index offset, Index size) { - CheckClosed(); - StreamOperationNotSupportedException::CheckRead(DoCanRead()); - return DoRead(buffer, offset, size); -} - -Index Stream::Read(std::byte* buffer, Index size) { - return Read(buffer, 0, size); -} - -Index Stream::Read(char* buffer, Index offset, Index size) { - return Read(reinterpret_cast(buffer), offset, size); -} - -Index Stream::Read(char* buffer, Index size) { - return Read(reinterpret_cast(buffer), 0, size); -} - -bool Stream::CanWrite() { - CheckClosed(); - return DoCanWrite(); -} - -Index Stream::Write(const std::byte* buffer, Index offset, Index size) { - CheckClosed(); - StreamOperationNotSupportedException::CheckWrite(DoCanWrite()); - return DoWrite(buffer, offset, size); -} - -Index Stream::Write(const std::byte* buffer, Index size) { - return Write(buffer, 0, size); -} - -Index Stream::Write(const char* buffer, Index offset, Index size) { - return Write(reinterpret_cast(buffer), offset, size); -} - -Index Stream::Write(const char* buffer, Index size) { - return Write(reinterpret_cast(buffer), size); -} - -void Stream::Flush() { - CheckClosed(); - DoFlush(); -} - -bool Stream::DoCanSeek() { - if (supported_operations_->can_seek) { - return *supported_operations_->can_seek; - } else { - throw Exception( - u"Can seek is neither set in supported_operations nor implemeted in " - u"virtual function."); - } -} - -bool Stream::DoCanRead() { - if (supported_operations_->can_read) { - return *supported_operations_->can_read; - } else { - throw Exception( - u"Can read is neither set in supported_operations nor implemeted in " - u"virtual function."); - } -} - -bool Stream::DoCanWrite() { - if (supported_operations_->can_write) { - return *supported_operations_->can_write; - } else { - throw Exception( - u"Can write is neither set in supported_operations nor implemeted in " - u"virtual function."); - } -} - -Index Stream::DoSeek(Index offset, SeekOrigin origin) { - throw Exception(u"Stream is seekable but DoSeek is not implemented."); -} - -Index Stream::DoTell() { - StreamOperationNotSupportedException::CheckSeek(DoCanSeek()); - return DoSeek(0, SeekOrigin::Current); -} - -void Stream::DoRewind() { - StreamOperationNotSupportedException::CheckSeek(DoCanSeek()); - DoSeek(0, SeekOrigin::Begin); -} - -Index Stream::DoGetSize() { - StreamOperationNotSupportedException::CheckSeek(DoCanSeek()); - Index current_position = DoTell(); - Seek(0, SeekOrigin::End); - Index size = DoTell(); - Seek(current_position, SeekOrigin::Begin); - return size; -} - -Index Stream::DoRead(std::byte* buffer, Index offset, Index size) { - throw Exception(u"Stream is readable but DoSeek is not implemented."); -} - -Index Stream::DoWrite(const std::byte* buffer, Index offset, Index size) { - throw Exception(u"Stream is writable but DoSeek is not implemented."); -} - -void Stream::DoFlush() {} - -Buffer Stream::ReadToEnd(Index grow_size) { - Buffer buffer(grow_size); - while (true) { - auto read = Read(buffer.GetUsedEndPtr(), buffer.GetBackFree()); - buffer.PushBackCount(read); - if (read == 0) { - break; - } - if (buffer.IsUsedReachEnd()) { - buffer.ResizeBuffer(buffer.GetBufferSize() + grow_size, true); - } - } - return buffer; -} - -String Stream::ReadToEndAsUtf8String() { - auto buffer = ReadToEnd(); - return String::FromUtf8(buffer); -} -} // namespace cru::io diff --git a/src/common/log/Logger.cpp b/src/common/log/Logger.cpp deleted file mode 100644 index 4b07ed87..00000000 --- a/src/common/log/Logger.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "cru/common/log/Logger.h" -#include "cru/common/log/StdioLogTarget.h" - -#include -#include - -#ifdef CRU_PLATFORM_WINDOWS -#include "cru/common/platform/win/DebugLogTarget.h" -#endif - -namespace cru::log { -Logger *Logger::GetInstance() { - static Logger logger; - - logger.AddLogTarget(std::make_unique()); - -#ifdef CRU_PLATFORM_WINDOWS - logger.AddLogTarget(std::make_unique()); -#endif - - return &logger; -} - -void Logger::AddLogTarget(std::unique_ptr target) { - std::lock_guard lock(target_list_mutex_); - target_list_.push_back(std::move(target)); -} - -void Logger::RemoveLogTarget(ILogTarget *target) { - std::lock_guard lock(target_list_mutex_); - target_list_.erase( - std::remove_if(target_list_.begin(), target_list_.end(), - [target](const auto &t) { return t.get() == target; }), - target_list_.end()); -} - -namespace { -String LogLevelToString(LogLevel level) { - switch (level) { - case LogLevel::Debug: - return u"DEBUG"; - case LogLevel::Info: - return u"INFO"; - case LogLevel::Warn: - return u"WARN"; - case LogLevel::Error: - return u"ERROR"; - default: - std::terminate(); - } -} - -String GetLogTime() { - auto time = std::time(nullptr); - auto calendar = std::localtime(&time); - return Format(u"{}:{}:{}", calendar->tm_hour, calendar->tm_min, - calendar->tm_sec); -} - -String MakeLogFinalMessage(const LogInfo &log_info) { - return Format(u"[{}] {} {}: {}\n", GetLogTime(), - LogLevelToString(log_info.level), log_info.tag, - log_info.message); -} -} // namespace - -Logger::Logger() - : log_thread_([this] { - while (true) { - auto log_info = log_queue_.Pull(); - std::lock_guard lock_guard{target_list_mutex_}; - for (const auto &target : target_list_) { - target->Write(log_info.level, MakeLogFinalMessage(log_info)); - } - } - }) {} - -Logger::~Logger() { log_thread_.detach(); } - -void Logger::Log(LogInfo log_info) { -#ifndef CRU_DEBUG - if (log_info.level == LogLevel::Debug) { - return; - } -#endif - log_queue_.Push(std::move(log_info)); -} -} // namespace cru::log diff --git a/src/common/log/StdioLogTarget.cpp b/src/common/log/StdioLogTarget.cpp deleted file mode 100644 index 7f99dbd1..00000000 --- a/src/common/log/StdioLogTarget.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "cru/common/log/StdioLogTarget.h" - -#include - -namespace cru::log { -StdioLogTarget::StdioLogTarget() {} - -StdioLogTarget::~StdioLogTarget() {} - -void StdioLogTarget::Write(log::LogLevel level, StringView s) { -#ifdef CRU_PLATFORM_WINDOWS - if (level == log::LogLevel::Error) { - std::wcerr.write(reinterpret_cast(s.data()), s.size()); - } else { - std::wcout.write(reinterpret_cast(s.data()), s.size()); - } -#else - std::string m = s.ToUtf8(); - - if (level == log::LogLevel::Error) { - std::cerr << m; - } else { - std::cout << m; - } -#endif -} -} // namespace cru::log diff --git a/src/common/platform/Exception.cpp b/src/common/platform/Exception.cpp deleted file mode 100644 index 1c5db390..00000000 --- a/src/common/platform/Exception.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "cru/common/platform/Exception.h" diff --git a/src/common/platform/osx/Convert.cpp b/src/common/platform/osx/Convert.cpp deleted file mode 100644 index 4792df1f..00000000 --- a/src/common/platform/osx/Convert.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "cru/common/platform/osx/Convert.h" - -namespace cru::platform::osx { -CFStringRef Convert(const String& string) { - return CFStringCreateWithBytes( - nullptr, reinterpret_cast(string.data()), - string.size() * sizeof(std::uint16_t), kCFStringEncodingUTF16, false); -} - -String Convert(CFStringRef string) { - auto length = CFStringGetLength(string); - - String result; - - for (int i = 0; i < length; i++) { - result.AppendCodePoint(CFStringGetCharacterAtIndex(string, i)); - } - - return result; -} - -CFRange Convert(const Range& range) { - return CFRangeMake(range.position, range.count); -} - -Range Convert(const CFRange& range) { - return Range(range.location, range.length); -} -} // namespace cru::platform::osx diff --git a/src/common/platform/osx/Exception.cpp b/src/common/platform/osx/Exception.cpp deleted file mode 100644 index e03faa4c..00000000 --- a/src/common/platform/osx/Exception.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "cru/common/platform//osx/Exception.h" diff --git a/src/common/platform/unix/PosixSpawnSubProcess.cpp b/src/common/platform/unix/PosixSpawnSubProcess.cpp deleted file mode 100644 index b5d68845..00000000 --- a/src/common/platform/unix/PosixSpawnSubProcess.cpp +++ /dev/null @@ -1,204 +0,0 @@ -#include "cru/common/platform/unix/PosixSpawnSubProcess.h" -#include "cru/common/Exception.h" -#include "cru/common/Format.h" -#include "cru/common/Guard.h" -#include "cru/common/String.h" -#include "cru/common/SubProcess.h" -#include "cru/common/log/Logger.h" - -#include -#include -#include -#include -#include -#include - -namespace cru::platform::unix { -PosixSpawnSubProcessImpl::PosixSpawnSubProcessImpl() - : pid_(0), - exit_code_(0), - stdin_pipe_(UnixPipe::Usage::Send, false), - stdout_pipe_(UnixPipe::Usage::Receive, false), - stderr_pipe_(UnixPipe::Usage::Receive, false) { - stdin_stream_ = std::make_unique( - stdin_pipe_.GetSelfFileDescriptor(), false, false, true, true); - stdout_stream_ = std::make_unique( - stdout_pipe_.GetSelfFileDescriptor(), false, true, false, true); - stderr_stream_ = std::make_unique( - stderr_pipe_.GetSelfFileDescriptor(), false, true, false, true); - - stdout_buffer_stream_ = - std::make_unique(stdout_stream_.get(), false); - stderr_buffer_stream_ = - std::make_unique(stderr_stream_.get(), false); -} - -PosixSpawnSubProcessImpl::~PosixSpawnSubProcessImpl() {} - -namespace { -char** CreateCstrArray(const std::vector& argv) { - std::vector utf8_argv; - for (const auto& arg : argv) { - utf8_argv.push_back(arg.ToUtf8Buffer()); - } - char** result = new char*[utf8_argv.size() + 1]; - for (int i = 0; i < utf8_argv.size(); i++) { - result[i] = reinterpret_cast(utf8_argv[i].Detach()); - } - result[utf8_argv.size()] = nullptr; - return result; -} - -char** CreateCstrArray(const std::unordered_map& envp) { - std::vector str_array; - for (auto& [key, value] : envp) { - str_array.push_back(cru::Format(u"{}={}", key, value)); - } - return CreateCstrArray(str_array); -} - -void DestroyCstrArray(char** argv) { - int index = 0; - char* arg = argv[index]; - while (arg) { - delete[] arg; - index++; - arg = argv[index]; - } - delete[] argv; -} -} // namespace - -void PosixSpawnSubProcessImpl::PlatformCreateProcess( - const SubProcessStartInfo& start_info) { - int error; - auto check_error = [&error](String message) { - if (error == 0) return; - std::unique_ptr inner(new ErrnoException({}, error)); - throw SubProcessFailedToStartException(std::move(message), - std::move(inner)); - }; - - posix_spawn_file_actions_t file_actions; - error = posix_spawn_file_actions_init(&file_actions); - check_error(u"Failed to call posix_spawn_file_actions_init."); - Guard file_actions_guard( - [&file_actions] { posix_spawn_file_actions_destroy(&file_actions); }); - - // dup2 stdin/stdout/stderr - error = posix_spawn_file_actions_adddup2( - &file_actions, stdin_pipe_.GetOtherFileDescriptor(), STDIN_FILENO); - check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdin."); - error = posix_spawn_file_actions_adddup2( - &file_actions, stdout_pipe_.GetOtherFileDescriptor(), STDOUT_FILENO); - check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdout."); - error = posix_spawn_file_actions_adddup2( - &file_actions, stderr_pipe_.GetOtherFileDescriptor(), STDERR_FILENO); - check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stderr."); - - error = posix_spawn_file_actions_addclose( - &file_actions, stdin_pipe_.GetOtherFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on self fd of stdin."); - error = posix_spawn_file_actions_addclose( - &file_actions, stdout_pipe_.GetOtherFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on self fd stdout."); - error = posix_spawn_file_actions_addclose( - &file_actions, stderr_pipe_.GetOtherFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on self fd stderr."); - - error = posix_spawn_file_actions_addclose( - &file_actions, stdin_pipe_.GetSelfFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on parent fd of " - u"stdin."); - error = posix_spawn_file_actions_addclose( - &file_actions, stdout_pipe_.GetSelfFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on parent fd of " - u"stdout."); - error = posix_spawn_file_actions_addclose( - &file_actions, stderr_pipe_.GetSelfFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on parent fd of " - u"stderr."); - - posix_spawnattr_t attr; - error = posix_spawnattr_init(&attr); - check_error(u"Failed to call posix_spawnattr_init."); - Guard attr_guard([&attr] { posix_spawnattr_destroy(&attr); }); - -#ifdef CRU_PLATFORM_OSX - error = posix_spawnattr_setflags(&attr, POSIX_SPAWN_CLOEXEC_DEFAULT); - check_error(u"Failed to set flag POSIX_SPAWN_CLOEXEC_DEFAULT (osx)."); -#endif - - auto exe = start_info.program.ToUtf8(); - std::vector arguments{start_info.program}; - arguments.insert(arguments.cend(), start_info.arguments.cbegin(), - start_info.arguments.cend()); - - auto argv = CreateCstrArray(arguments); - Guard argv_guard([argv] { DestroyCstrArray(argv); }); - - auto envp = CreateCstrArray(start_info.environments); - Guard envp_guard([envp] { DestroyCstrArray(envp); }); - - error = posix_spawnp(&pid_, exe.c_str(), &file_actions, &attr, argv, envp); - check_error(u"Failed to call posix_spawnp."); - - error = ::close(stdin_pipe_.GetOtherFileDescriptor()); - check_error(u"Failed to close child stdin."); - error = ::close(stdout_pipe_.GetOtherFileDescriptor()); - check_error(u"Failed to close child stdout."); - error = ::close(stderr_pipe_.GetOtherFileDescriptor()); - check_error(u"Failed to close child stderr."); -} - -SubProcessExitResult PosixSpawnSubProcessImpl::PlatformWaitForProcess() { - int wstatus; - - while (waitpid(pid_, &wstatus, 0) == -1) { - if (errno == EINTR) { - CRU_LOG_INFO(u"Waitpid is interrupted by a signal. Call it again."); - continue; - } - - std::unique_ptr inner(new ErrnoException({}, errno)); - - throw SubProcessInternalException( - u"Failed to call waitpid on a subprocess.", std::move(inner)); - } - - if (WIFEXITED(wstatus)) { - return SubProcessExitResult::Normal(WEXITSTATUS(wstatus)); - } else if (WIFEXITED(wstatus)) { - return SubProcessExitResult::Signal(WTERMSIG(wstatus), WCOREDUMP(wstatus)); - } else { - return SubProcessExitResult::Unknown(); - } -} - -void PosixSpawnSubProcessImpl::PlatformKillProcess() { - int error = kill(pid_, SIGKILL); - if (error != 0) { - std::unique_ptr inner(new ErrnoException({}, errno)); - throw SubProcessInternalException(u"Failed to call kill on a subprocess.", - std::move(inner)); - } -} - -io::Stream* PosixSpawnSubProcessImpl::GetStdinStream() { - return stdin_stream_.get(); -} - -io::Stream* PosixSpawnSubProcessImpl::GetStdoutStream() { - return stdout_buffer_stream_.get(); -} - -io::Stream* PosixSpawnSubProcessImpl::GetStderrStream() { - return stderr_buffer_stream_.get(); -} -} // namespace cru::platform::unix diff --git a/src/common/platform/unix/UnixFileStream.cpp b/src/common/platform/unix/UnixFileStream.cpp deleted file mode 100644 index 804e24f0..00000000 --- a/src/common/platform/unix/UnixFileStream.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "cru/common/platform/unix/UnixFileStream.h" -#include "cru/common/Exception.h" -#include "cru/common/Format.h" -#include "cru/common/io/Stream.h" -#include "cru/common/log/Logger.h" - -#include -#include -#include -#include - -namespace cru::platform::unix { -using namespace cru::io; - -namespace { -bool OflagCanSeek([[maybe_unused]] int oflag) { - // Treat every file seekable. - return true; -} - -bool OflagCanRead(int oflag) { - // There is a problem: O_RDONLY is 0. So we must test it specially. - // If it is not write-only. Then it can read. - return !(oflag & O_WRONLY); -} - -bool OflagCanWrite(int oflag) { return oflag & O_WRONLY || oflag & O_RDWR; } - -int MapSeekOrigin(Stream::SeekOrigin origin) { - switch (origin) { - case Stream::SeekOrigin::Begin: - return SEEK_SET; - case Stream::SeekOrigin::Current: - return SEEK_CUR; - case Stream::SeekOrigin::End: - return SEEK_END; - default: - throw Exception(u"Invalid seek origin."); - } -} -} // namespace - -UnixFileStream::UnixFileStream(const char *path, int oflag, mode_t mode) { - file_descriptor_ = ::open(path, oflag, mode); - if (file_descriptor_ == -1) { - throw ErrnoException( - Format(u"Failed to open file {} with oflag {}, mode {}.", - String::FromUtf8(path), oflag, mode)); - } - - SetSupportedOperations( - {OflagCanSeek(oflag), OflagCanRead(oflag), OflagCanWrite(oflag)}); - - auto_close_ = true; -} - -UnixFileStream::UnixFileStream(int fd, bool can_seek, bool can_read, - bool can_write, bool auto_close) - : Stream(can_seek, can_read, can_write) { - file_descriptor_ = fd; - auto_close_ = auto_close; -} - -UnixFileStream::~UnixFileStream() { - if (auto_close_ && file_descriptor_ >= 0) { - if (::close(file_descriptor_) == -1) { - // We are in destructor, so we can not throw. - CRU_LOG_WARN(u"Failed to close file descriptor {}, errno {}.", - file_descriptor_, errno); - } - } -} - -Index UnixFileStream::DoSeek(Index offset, SeekOrigin origin) { - off_t result = ::lseek(file_descriptor_, offset, MapSeekOrigin(origin)); - if (result == -1) { - throw ErrnoException(u"Failed to seek file."); - } - return result; -} - -Index UnixFileStream::DoRead(std::byte *buffer, Index offset, Index size) { - auto result = ::read(file_descriptor_, buffer + offset, size); - if (result == -1) { - throw ErrnoException(u"Failed to read file."); - } - return result; -} - -Index UnixFileStream::DoWrite(const std::byte *buffer, Index offset, - Index size) { - auto result = ::write(file_descriptor_, buffer + offset, size); - if (result == -1) { - throw ErrnoException(u"Failed to write file."); - } - return result; -} - -void UnixFileStream::DoClose() { - CRU_STREAM_BEGIN_CLOSE - if (auto_close_ && ::close(file_descriptor_) == -1) { - throw ErrnoException(u"Failed to close file."); - } - file_descriptor_ = -1; -} -} // namespace cru::platform::unix diff --git a/src/common/platform/unix/UnixPipe.cpp b/src/common/platform/unix/UnixPipe.cpp deleted file mode 100644 index f30c599e..00000000 --- a/src/common/platform/unix/UnixPipe.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "cru/common/platform/unix/UnixPipe.h" -#include "cru/common/Exception.h" -#include "cru/common/log/Logger.h" - -#include -#include -#include - -namespace cru::platform::unix { -UnixPipe::UnixPipe(Usage usage, bool auto_close, UnixPipeFlag flags) - : usage_(usage), auto_close_(auto_close), flags_(flags) { - int fds[2]; - if (pipe(fds) != 0) { - throw ErrnoException(u"Failed to create unix pipe."); - } - - if (flags & UnixPipeFlags::NonBlock) { - fcntl(fds[0], F_SETFL, O_NONBLOCK); - fcntl(fds[1], F_SETFL, O_NONBLOCK); - } - - read_fd_ = fds[0]; - write_fd_ = fds[1]; -} - -int UnixPipe::GetSelfFileDescriptor() { - if (usage_ == Usage::Send) { - return write_fd_; - } else { - return read_fd_; - } -} - -int UnixPipe::GetOtherFileDescriptor() { - if (usage_ == Usage::Send) { - return read_fd_; - } else { - return write_fd_; - } -} - -UnixPipe::~UnixPipe() { - if (auto_close_) { - auto self_fd = GetSelfFileDescriptor(); - if (::close(self_fd) != 0) { - CRU_LOG_ERROR(u"Failed to close unix pipe file descriptor {}, errno {}.", - self_fd, errno); - } - } -} -} // namespace cru::platform::unix diff --git a/src/common/platform/web/WebException.cpp b/src/common/platform/web/WebException.cpp deleted file mode 100644 index 30f9d1f0..00000000 --- a/src/common/platform/web/WebException.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "cru/common/platform/web/WebException.h" diff --git a/src/common/platform/win/BridgeComStream.cpp b/src/common/platform/win/BridgeComStream.cpp deleted file mode 100644 index 4c83fd45..00000000 --- a/src/common/platform/win/BridgeComStream.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "BrigdeComStream.h" -#include "cru/common/io/Stream.h" - -namespace cru::platform::win { -BridgeComStream::BridgeComStream(io::Stream *stream) - : stream_(stream), ref_count_(1) {} - -BridgeComStream::~BridgeComStream() {} - -ULONG BridgeComStream::AddRef() { return ++ref_count_; } - -ULONG BridgeComStream::Release() { - --ref_count_; - - if (ref_count_ == 0) { - delete this; - return 0; - } - - return ref_count_; -} - -HRESULT BridgeComStream::QueryInterface(const IID &riid, void **ppvObject) { - if (riid == IID_IStream) { - *ppvObject = static_cast(this); - AddRef(); - return S_OK; - } else if (riid == IID_ISequentialStream) { - *ppvObject = static_cast(this); - AddRef(); - return S_OK; - } else if (riid == IID_IUnknown) { - *ppvObject = static_cast(this); - AddRef(); - return S_OK; - } else { - return E_NOINTERFACE; - } -} - -HRESULT BridgeComStream::Read(void *pv, ULONG cb, ULONG *pcbRead) { - *pcbRead = stream_->Read(static_cast(pv), cb); - return S_OK; -} - -HRESULT BridgeComStream::Write(const void *pv, ULONG cb, ULONG *pcbWritten) { - *pcbWritten = stream_->Write(static_cast(pv), cb); - return S_OK; -} - -HRESULT BridgeComStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, - ULARGE_INTEGER *plibNewPosition) { - io::Stream::SeekOrigin so; - - switch (dwOrigin) { - case STREAM_SEEK_SET: - so = io::Stream::SeekOrigin::Begin; - break; - case STREAM_SEEK_CUR: - so = io::Stream::SeekOrigin::Current; - break; - case STREAM_SEEK_END: - so = io::Stream::SeekOrigin::End; - break; - default: - return STG_E_INVALIDFUNCTION; - }; - - plibNewPosition->QuadPart = stream_->Seek(dlibMove.QuadPart, so); - return S_OK; -} - -HRESULT BridgeComStream::SetSize(ULARGE_INTEGER libNewSize) { - return E_NOTIMPL; -} - -HRESULT BridgeComStream::CopyTo(IStream *pstm, ULARGE_INTEGER cb, - ULARGE_INTEGER *pcbRead, - ULARGE_INTEGER *pcbWritten) { - return E_NOTIMPL; -} - -HRESULT BridgeComStream::Commit(DWORD grfCommitFlags) { return S_OK; } - -HRESULT BridgeComStream::Revert() { return S_OK; } - -HRESULT BridgeComStream::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, - DWORD dwLockType) { - return S_OK; -} - -HRESULT BridgeComStream::UnlockRegion(ULARGE_INTEGER libOffset, - ULARGE_INTEGER cb, DWORD dwLockType) { - return S_OK; -} - -HRESULT BridgeComStream::Stat(STATSTG *pstatstg, DWORD grfStatFlag) { - return E_NOTIMPL; -} - -HRESULT BridgeComStream::Clone(IStream **ppstm) { - *ppstm = new BridgeComStream(stream_); - return S_OK; -} - -} // namespace cru::platform::win diff --git a/src/common/platform/win/BrigdeComStream.h b/src/common/platform/win/BrigdeComStream.h deleted file mode 100644 index 7c8a79d1..00000000 --- a/src/common/platform/win/BrigdeComStream.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#include "cru/common/platform/win/WinPreConfig.h" - -#include "cru/common/io/Stream.h" - -#include - -namespace cru::platform::win { -class BridgeComStream : public IStream { - public: - explicit BridgeComStream(io::Stream* stream); - - CRU_DELETE_COPY(BridgeComStream) - CRU_DELETE_MOVE(BridgeComStream) - - ~BridgeComStream(); - - public: - ULONG AddRef() override; - ULONG Release() override; - HRESULT QueryInterface(REFIID riid, void** ppvObject) override; - - HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) override; - HRESULT Write(const void* pv, ULONG cb, ULONG* pcbWritten) override; - HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, - ULARGE_INTEGER* plibNewPosition) override; - HRESULT SetSize(ULARGE_INTEGER libNewSize) override; - HRESULT CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, - ULARGE_INTEGER* pcbWritten) override; - HRESULT Commit(DWORD grfCommitFlags) override; - HRESULT Revert() override; - HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, - DWORD dwLockType) override; - HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, - DWORD dwLockType) override; - HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) override; - HRESULT Clone(IStream** ppstm) override; - - private: - io::Stream* stream_; - ULONG ref_count_; -}; -} // namespace cru::platform::win diff --git a/src/common/platform/win/ComAutoInit.cpp b/src/common/platform/win/ComAutoInit.cpp deleted file mode 100644 index 55a53a8d..00000000 --- a/src/common/platform/win/ComAutoInit.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "cru/common/platform/win/ComAutoInit.h" -#include "cru/common/platform/win/Exception.h" - -#include - -namespace cru::platform::win { -ComAutoInit::ComAutoInit() { - const auto hresult = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - if (FAILED(hresult)) { - throw HResultError(hresult, "Failed to call CoInitializeEx."); - } -} - -ComAutoInit::~ComAutoInit() { ::CoUninitialize(); } -} // namespace cru::platform::win diff --git a/src/common/platform/win/DebugLogTarget.cpp b/src/common/platform/win/DebugLogTarget.cpp deleted file mode 100644 index 92d26449..00000000 --- a/src/common/platform/win/DebugLogTarget.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "cru/common/platform/win/DebugLogTarget.h" - -namespace cru::platform::win { -void WinDebugLogTarget::Write(::cru::log::LogLevel level, StringView s) { - CRU_UNUSED(level) - - String m = s.ToString(); - ::OutputDebugStringW(reinterpret_cast(m.c_str())); -} -} // namespace cru::platform::win diff --git a/src/common/platform/win/Exception.cpp b/src/common/platform/win/Exception.cpp deleted file mode 100644 index a20e8a31..00000000 --- a/src/common/platform/win/Exception.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "cru/common/platform/win/Exception.h" -#include "cru/common/Format.h" - -#include - -namespace cru::platform::win { - -inline String HResultMakeMessage(HRESULT h_result, - std::optional message) { - if (message.has_value()) - return Format(u"HRESULT: {}. Message: {}", h_result, message->WinCStr()); - else - return Format(u"HRESULT: {}.", h_result); -} - -HResultError::HResultError(HRESULT h_result) - : PlatformException(HResultMakeMessage(h_result, std::nullopt)), - h_result_(h_result) {} - -HResultError::HResultError(HRESULT h_result, - std::string_view additional_message) - : PlatformException(HResultMakeMessage( - h_result, String::FromUtf8(additional_message.data(), - additional_message.size()))), - h_result_(h_result) {} - -inline String Win32MakeMessage(DWORD error_code, String message) { - return Format(u"Last error code: {}.\nMessage: {}\n", error_code, - message.WinCStr()); -} - -Win32Error::Win32Error(String message) - : Win32Error(::GetLastError(), message) {} - -Win32Error::Win32Error(DWORD error_code, String message) - : PlatformException(Win32MakeMessage(error_code, message)), - error_code_(error_code) {} -} // namespace cru::platform::win diff --git a/src/common/platform/win/StreamConvert.cpp b/src/common/platform/win/StreamConvert.cpp deleted file mode 100644 index d547caa5..00000000 --- a/src/common/platform/win/StreamConvert.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "cru/common/platform/win/StreamConvert.h" -#include "BrigdeComStream.h" -#include "Win32FileStreamPrivate.h" -#include "cru/common/Exception.h" -#include "cru/common/io/MemoryStream.h" -#include "cru/common/io/OpenFileFlag.h" -#include "cru/common/platform/win/ComAutoInit.h" -#include "cru/common/platform/win/Exception.h" -#include "cru/common/platform/win/Win32FileStream.h" - -#include -#include - -namespace cru::platform::win { -IStream* ConvertStreamToComStream(io::Stream* stream) { - static ComAutoInit com_auto_init; - - if (auto memory_stream = dynamic_cast(stream)) { - return SHCreateMemStream( - reinterpret_cast(memory_stream->GetBuffer()), - memory_stream->GetSize()); - } else if (auto file_stream = dynamic_cast(stream)) { - return file_stream->GetPrivate_()->stream_; - } else { - return new BridgeComStream(stream); - } -} -} // namespace cru::platform::win diff --git a/src/common/platform/win/Win32FileStream.cpp b/src/common/platform/win/Win32FileStream.cpp deleted file mode 100644 index a118dc02..00000000 --- a/src/common/platform/win/Win32FileStream.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "cru/common/platform/win/Win32FileStream.h" - -#include "Win32FileStreamPrivate.h" -#include "cru/common/io/OpenFileFlag.h" -#include "cru/common/platform/win/Exception.h" - -#include -#include -#include -#include -#include - -namespace cru::platform::win { -using namespace cru::io; - -Win32FileStream::Win32FileStream(String path, OpenFileFlag flags) - : path_(std::move(path)), - flags_(flags), - p_(new details::Win32FileStreamPrivate()) { - DWORD grfMode = STGM_SHARE_DENY_NONE; - if (flags & io::OpenFileFlags::Read) { - if (flags & io::OpenFileFlags::Write) { - grfMode |= STGM_READWRITE; - } else { - grfMode |= STGM_READ; - } - } else { - if (flags & io::OpenFileFlags::Write) { - grfMode |= STGM_WRITE; - } else { - throw Exception(u"Stream must be readable or writable."); - } - } - - if (flags & io::OpenFileFlags::Truncate) { - grfMode |= STGM_CREATE; - } - - IStream* stream; - - ThrowIfFailed(SHCreateStreamOnFileEx( - path_.WinCStr(), grfMode, FILE_ATTRIBUTE_NORMAL, - flags & io::OpenFileFlags::Create ? TRUE : FALSE, NULL, &stream)); - - p_->stream_ = stream; -} - -Win32FileStream::~Win32FileStream() { - Close(); - delete p_; -} - -bool Win32FileStream::CanSeek() { return true; } - -Index Win32FileStream::Seek(Index offset, SeekOrigin origin) { - CheckClosed(); - - DWORD dwOrigin = 0; - - if (origin == SeekOrigin::Current) { - dwOrigin = STREAM_SEEK_CUR; - } else if (origin == SeekOrigin::End) { - dwOrigin = STREAM_SEEK_END; - } else { - dwOrigin = STREAM_SEEK_SET; - } - - LARGE_INTEGER n_offset; - n_offset.QuadPart = offset; - ULARGE_INTEGER n_new_offset; - - ThrowIfFailed(p_->stream_->Seek(n_offset, dwOrigin, &n_new_offset)); - - return n_new_offset.QuadPart; -} - -bool Win32FileStream::CanRead() { return true; } - -Index Win32FileStream::Read(std::byte* buffer, Index offset, Index size) { - if (size < 0) { - throw Exception(u"Size must be greater than 0."); - } - - CheckClosed(); - - ULONG n_read; - ThrowIfFailed(p_->stream_->Read(buffer + offset, size, &n_read)); - return n_read; -} - -bool Win32FileStream::CanWrite() { return true; } - -Index Win32FileStream::Write(const std::byte* buffer, Index offset, - Index size) { - if (size < 0) { - throw Exception(u"Size must be greater than 0."); - } - - CheckClosed(); - - ULONG n_written; - ThrowIfFailed(p_->stream_->Write(buffer + offset, size, &n_written)); - - return n_written; -} - -void Win32FileStream::Close() { - if (closed_) return; - - if (p_->stream_) { - p_->stream_->Release(); - p_->stream_ = nullptr; - } - - closed_ = true; -} - -void Win32FileStream::CheckClosed() { - if (closed_) throw Exception(u"Stream is closed."); -} - -} // namespace cru::platform::win diff --git a/src/common/platform/win/Win32FileStreamPrivate.h b/src/common/platform/win/Win32FileStreamPrivate.h deleted file mode 100644 index 24492f8d..00000000 --- a/src/common/platform/win/Win32FileStreamPrivate.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "cru/common/platform/win/WinPreConfig.h" - -#include - -namespace cru::platform::win { - -namespace details { -struct Win32FileStreamPrivate { - IStream* stream_ = nullptr; -}; -} // namespace details - -} // namespace cru::platform::win diff --git a/src/parse/Grammar.cpp b/src/parse/Grammar.cpp index 17978adc..12617de3 100644 --- a/src/parse/Grammar.cpp +++ b/src/parse/Grammar.cpp @@ -1,7 +1,7 @@ #include "cru/parse/Grammar.h" -#include "cru/common/String.h" +#include "cru/base/String.h" #include "cru/parse/Symbol.h" -#include "cru/common/Format.h" +#include "cru/base/Format.h" #include #include diff --git a/src/platform/Exception.cpp b/src/platform/Exception.cpp index 7aef3b7f..948345e0 100644 --- a/src/platform/Exception.cpp +++ b/src/platform/Exception.cpp @@ -1,5 +1,5 @@ #include "cru/platform/Exception.h" -#include "cru/common/Format.h" +#include "cru/base/Format.h" #include diff --git a/src/platform/graphics/Geometry.cpp b/src/platform/graphics/Geometry.cpp index 0c98b456..25dfba6e 100644 --- a/src/platform/graphics/Geometry.cpp +++ b/src/platform/graphics/Geometry.cpp @@ -1,6 +1,6 @@ #include "cru/platform/graphics/Geometry.h" -#include "cru/common/Exception.h" +#include "cru/base/Exception.h" #include "cru/platform/Exception.h" #include "cru/platform/graphics/Factory.h" diff --git a/src/platform/graphics/cairo/CairoImageFactory.cpp b/src/platform/graphics/cairo/CairoImageFactory.cpp index 99994226..912226d9 100644 --- a/src/platform/graphics/cairo/CairoImageFactory.cpp +++ b/src/platform/graphics/cairo/CairoImageFactory.cpp @@ -1,5 +1,5 @@ #include "cru/platform/graphics/cairo/CairoImageFactory.h" -#include "cru/common/Exception.h" +#include "cru/base/Exception.h" #include "cru/platform/Check.h" #include "cru/platform/graphics/cairo/CairoImage.h" #include "cru/platform/graphics/cairo/CairoResource.h" diff --git a/src/platform/graphics/cairo/CairoPainter.cpp b/src/platform/graphics/cairo/CairoPainter.cpp index 00c8187c..b9ab50c4 100644 --- a/src/platform/graphics/cairo/CairoPainter.cpp +++ b/src/platform/graphics/cairo/CairoPainter.cpp @@ -1,5 +1,5 @@ #include "cru/platform/graphics/cairo/CairoPainter.h" -#include "cru/common/Exception.h" +#include "cru/base/Exception.h" #include "cru/platform/Check.h" #include "cru/platform/Exception.h" #include "cru/platform/graphics/cairo/Base.h" diff --git a/src/platform/graphics/cairo/PangoTextLayout.cpp b/src/platform/graphics/cairo/PangoTextLayout.cpp index 25e84707..1033ce9e 100644 --- a/src/platform/graphics/cairo/PangoTextLayout.cpp +++ b/src/platform/graphics/cairo/PangoTextLayout.cpp @@ -1,5 +1,5 @@ #include "cru/platform/graphics/cairo/PangoTextLayout.h" -#include "cru/common/StringUtil.h" +#include "cru/base/StringUtil.h" #include "cru/platform/Check.h" #include "cru/platform/GraphicsBase.h" #include "cru/platform/graphics/Base.h" diff --git a/src/platform/graphics/direct2d/Factory.cpp b/src/platform/graphics/direct2d/Factory.cpp index c35c53cf..cf65c2a5 100644 --- a/src/platform/graphics/direct2d/Factory.cpp +++ b/src/platform/graphics/direct2d/Factory.cpp @@ -1,6 +1,6 @@ #include "cru/platform/graphics/direct2d/Factory.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/graphics/direct2d/Brush.h" #include "cru/platform/graphics/direct2d/Exception.h" #include "cru/platform/graphics/direct2d/Font.h" diff --git a/src/platform/graphics/direct2d/Font.cpp b/src/platform/graphics/direct2d/Font.cpp index afbc9049..b1c03751 100644 --- a/src/platform/graphics/direct2d/Font.cpp +++ b/src/platform/graphics/direct2d/Font.cpp @@ -1,6 +1,6 @@ #include "cru/platform/graphics/direct2d/Font.h" -#include "cru/common/Format.h" +#include "cru/base/Format.h" #include "cru/platform/graphics/direct2d/Exception.h" #include "cru/platform/graphics/direct2d/Factory.h" diff --git a/src/platform/graphics/direct2d/Geometry.cpp b/src/platform/graphics/direct2d/Geometry.cpp index b84a901e..a2377400 100644 --- a/src/platform/graphics/direct2d/Geometry.cpp +++ b/src/platform/graphics/direct2d/Geometry.cpp @@ -1,6 +1,6 @@ #include "cru/platform/graphics/direct2d/Geometry.h" -#include "cru/common/platform/win/Exception.h" +#include "cru/base/platform/win/Exception.h" #include "cru/platform/graphics/direct2d/ConvertUtil.h" #include "cru/platform/graphics/direct2d/Exception.h" #include "cru/platform/graphics/direct2d/Factory.h" diff --git a/src/platform/graphics/direct2d/Image.cpp b/src/platform/graphics/direct2d/Image.cpp index 78cccd6a..2f60b373 100644 --- a/src/platform/graphics/direct2d/Image.cpp +++ b/src/platform/graphics/direct2d/Image.cpp @@ -1,6 +1,6 @@ #include "cru/platform/graphics/direct2d/Image.h" #include -#include "cru/common/platform/win/Exception.h" +#include "cru/base/platform/win/Exception.h" #include "cru/platform/graphics/direct2d/ConvertUtil.h" #include "cru/platform/graphics/direct2d/Exception.h" #include "cru/platform/graphics/direct2d/Factory.h" diff --git a/src/platform/graphics/direct2d/ImageFactory.cpp b/src/platform/graphics/direct2d/ImageFactory.cpp index 7cbc0ad4..113f70c8 100644 --- a/src/platform/graphics/direct2d/ImageFactory.cpp +++ b/src/platform/graphics/direct2d/ImageFactory.cpp @@ -1,6 +1,6 @@ #include "cru/platform/graphics/direct2d/ImageFactory.h" -#include "cru/common/platform/win/Exception.h" -#include "cru/common/platform/win/StreamConvert.h" +#include "cru/base/platform/win/Exception.h" +#include "cru/base/platform/win/StreamConvert.h" #include "cru/platform/Check.h" #include "cru/platform/graphics/direct2d/Exception.h" #include "cru/platform/graphics/direct2d/Factory.h" diff --git a/src/platform/graphics/direct2d/Painter.cpp b/src/platform/graphics/direct2d/Painter.cpp index dea3ba03..95b0bb4e 100644 --- a/src/platform/graphics/direct2d/Painter.cpp +++ b/src/platform/graphics/direct2d/Painter.cpp @@ -1,6 +1,6 @@ #include "cru/platform/graphics/direct2d/Painter.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/Check.h" #include "cru/platform/graphics/direct2d/Brush.h" #include "cru/platform/graphics/direct2d/ConvertUtil.h" diff --git a/src/platform/graphics/direct2d/TextLayout.cpp b/src/platform/graphics/direct2d/TextLayout.cpp index 5bc392de..06bbcaa6 100644 --- a/src/platform/graphics/direct2d/TextLayout.cpp +++ b/src/platform/graphics/direct2d/TextLayout.cpp @@ -1,7 +1,7 @@ #include "cru/platform/graphics/direct2d/TextLayout.h" #include -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/Check.h" #include "cru/platform/graphics/direct2d/Exception.h" #include "cru/platform/graphics/direct2d/Factory.h" diff --git a/src/platform/graphics/quartz/Brush.cpp b/src/platform/graphics/quartz/Brush.cpp index 2aa31bd8..ea740eb3 100644 --- a/src/platform/graphics/quartz/Brush.cpp +++ b/src/platform/graphics/quartz/Brush.cpp @@ -1,6 +1,6 @@ #include "cru/platform/graphics/quartz/Brush.h" -#include "cru/common/String.h" -#include "cru/common/Format.h" +#include "cru/base/String.h" +#include "cru/base/Format.h" namespace cru::platform::graphics::quartz { QuartzSolidColorBrush::QuartzSolidColorBrush(IGraphicsFactory* graphics_factory, diff --git a/src/platform/graphics/quartz/Image.cpp b/src/platform/graphics/quartz/Image.cpp index 3fa40937..966ce6be 100644 --- a/src/platform/graphics/quartz/Image.cpp +++ b/src/platform/graphics/quartz/Image.cpp @@ -1,5 +1,5 @@ #include "cru/platform/graphics/quartz/Image.h" -#include "cru/common/Exception.h" +#include "cru/base/Exception.h" #include "cru/platform/graphics/quartz/Convert.h" #include "cru/platform/graphics/quartz/Painter.h" diff --git a/src/platform/graphics/quartz/ImageFactory.cpp b/src/platform/graphics/quartz/ImageFactory.cpp index a48b4b86..0557afa9 100644 --- a/src/platform/graphics/quartz/ImageFactory.cpp +++ b/src/platform/graphics/quartz/ImageFactory.cpp @@ -1,6 +1,6 @@ #include "cru/platform/graphics/quartz/ImageFactory.h" -#include "cru/common/Exception.h" -#include "cru/common/platform/osx/Convert.h" +#include "cru/base/Exception.h" +#include "cru/base/platform/osx/Convert.h" #include "cru/platform/graphics/quartz/Convert.h" #include "cru/platform/graphics/quartz/Image.h" #include "cru/platform/Check.h" diff --git a/src/platform/graphics/quartz/TextLayout.cpp b/src/platform/graphics/quartz/TextLayout.cpp index 24fd71ef..9e18ac85 100644 --- a/src/platform/graphics/quartz/TextLayout.cpp +++ b/src/platform/graphics/quartz/TextLayout.cpp @@ -1,7 +1,7 @@ #include "cru/platform/graphics/quartz/TextLayout.h" -#include "cru/common/Base.h" -#include "cru/common/Format.h" -#include "cru/common/StringUtil.h" +#include "cru/base/Base.h" +#include "cru/base/Format.h" +#include "cru/base/StringUtil.h" #include "cru/platform/osx/Convert.h" #include "cru/platform/graphics/quartz/Convert.h" #include "cru/platform/graphics/quartz/Resource.h" diff --git a/src/platform/gui/osx/Clipboard.mm b/src/platform/gui/osx/Clipboard.mm index 068771c8..5d498d0e 100644 --- a/src/platform/gui/osx/Clipboard.mm +++ b/src/platform/gui/osx/Clipboard.mm @@ -1,7 +1,7 @@ #include "cru/platform/gui/osx/Clipboard.h" #include "ClipboardPrivate.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/osx/Convert.h" #include diff --git a/src/platform/gui/osx/ClipboardPrivate.h b/src/platform/gui/osx/ClipboardPrivate.h index e00c59dc..766026b6 100644 --- a/src/platform/gui/osx/ClipboardPrivate.h +++ b/src/platform/gui/osx/ClipboardPrivate.h @@ -1,5 +1,5 @@ #pragma once -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/gui/osx/Clipboard.h" #include diff --git a/src/platform/gui/osx/InputMethod.mm b/src/platform/gui/osx/InputMethod.mm index 50ff80de..af2d1ec2 100644 --- a/src/platform/gui/osx/InputMethod.mm +++ b/src/platform/gui/osx/InputMethod.mm @@ -3,7 +3,7 @@ #import #include "InputMethodPrivate.h" #include "WindowPrivate.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/osx/Convert.h" #include "cru/platform/gui/osx/Window.h" diff --git a/src/platform/gui/osx/Menu.mm b/src/platform/gui/osx/Menu.mm index 568a5208..e74ec23b 100644 --- a/src/platform/gui/osx/Menu.mm +++ b/src/platform/gui/osx/Menu.mm @@ -2,7 +2,7 @@ #import "MenuPrivate.h" #include "KeyboardPrivate.h" -#include "cru/common/platform/osx/Convert.h" +#include "cru/base/platform/osx/Convert.h" #import diff --git a/src/platform/gui/osx/UiApplication.mm b/src/platform/gui/osx/UiApplication.mm index ef62af58..fd6e8ef0 100644 --- a/src/platform/gui/osx/UiApplication.mm +++ b/src/platform/gui/osx/UiApplication.mm @@ -1,8 +1,8 @@ #include "cru/platform/gui/osx/UiApplication.h" #include "ClipboardPrivate.h" -#include "cru/common/log/Logger.h" -#include "cru/common/platform/osx/Convert.h" +#include "cru/base/log/Logger.h" +#include "cru/base/platform/osx/Convert.h" #include "cru/platform/graphics/quartz/Factory.h" #include "cru/platform/gui/osx/Clipboard.h" #include "cru/platform/gui/osx/Cursor.h" diff --git a/src/platform/gui/osx/Window.mm b/src/platform/gui/osx/Window.mm index d6bee564..8c059a12 100644 --- a/src/platform/gui/osx/Window.mm +++ b/src/platform/gui/osx/Window.mm @@ -3,8 +3,8 @@ #include "CursorPrivate.h" #include "InputMethodPrivate.h" -#include "cru/common/Range.h" -#include "cru/common/log/Logger.h" +#include "cru/base/Range.h" +#include "cru/base/log/Logger.h" #include "cru/platform/Check.h" #include "cru/platform/graphics/NullPainter.h" #include "cru/platform/graphics/quartz/Convert.h" diff --git a/src/platform/gui/osx/WindowPrivate.h b/src/platform/gui/osx/WindowPrivate.h index 00e15084..478ce4e5 100644 --- a/src/platform/gui/osx/WindowPrivate.h +++ b/src/platform/gui/osx/WindowPrivate.h @@ -1,7 +1,7 @@ #pragma once #include "cru/platform/gui/osx/Window.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/platform/gui/TimerHelper.h" #include "cru/platform/gui/Window.h" #include "cru/platform/gui/osx/Cursor.h" diff --git a/src/platform/gui/win/Clipboard.cpp b/src/platform/gui/win/Clipboard.cpp index 26850d3d..a0914a0b 100644 --- a/src/platform/gui/win/Clipboard.cpp +++ b/src/platform/gui/win/Clipboard.cpp @@ -1,5 +1,5 @@ #include "cru/platform/gui/win/Clipboard.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/gui/win/GodWindow.h" #include "cru/platform/gui/win/UiApplication.h" diff --git a/src/platform/gui/win/Cursor.cpp b/src/platform/gui/win/Cursor.cpp index c2efff1b..d7692c2d 100644 --- a/src/platform/gui/win/Cursor.cpp +++ b/src/platform/gui/win/Cursor.cpp @@ -1,6 +1,6 @@ #include "cru/platform/gui/win/Cursor.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/gui/win/Exception.h" #include diff --git a/src/platform/gui/win/GodWindow.cpp b/src/platform/gui/win/GodWindow.cpp index 4a062369..364688e5 100644 --- a/src/platform/gui/win/GodWindow.cpp +++ b/src/platform/gui/win/GodWindow.cpp @@ -1,6 +1,6 @@ #include "cru/platform/gui/win/GodWindow.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/gui/win/Exception.h" #include "cru/platform/gui/win/UiApplication.h" #include "cru/platform/gui/win/WindowClass.h" diff --git a/src/platform/gui/win/InputMethod.cpp b/src/platform/gui/win/InputMethod.cpp index 4c5b3b8c..44b5681d 100644 --- a/src/platform/gui/win/InputMethod.cpp +++ b/src/platform/gui/win/InputMethod.cpp @@ -1,7 +1,7 @@ #include "cru/platform/gui/win/InputMethod.h" -#include "cru/common/StringUtil.h" -#include "cru/common/log/Logger.h" +#include "cru/base/StringUtil.h" +#include "cru/base/log/Logger.h" #include "cru/platform/Check.h" #include "cru/platform/gui/DebugFlags.h" #include "cru/platform/gui/win/Exception.h" diff --git a/src/platform/gui/win/TimerManager.h b/src/platform/gui/win/TimerManager.h index 21c00690..b3f4aa38 100644 --- a/src/platform/gui/win/TimerManager.h +++ b/src/platform/gui/win/TimerManager.h @@ -1,8 +1,8 @@ #pragma once -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/platform/win/WinPreConfig.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/gui/win/GodWindow.h" #include "cru/platform/gui/win/WindowNativeMessageEventArgs.h" diff --git a/src/platform/gui/win/UiApplication.cpp b/src/platform/gui/win/UiApplication.cpp index 94d6b9c5..5be1a5d2 100644 --- a/src/platform/gui/win/UiApplication.cpp +++ b/src/platform/gui/win/UiApplication.cpp @@ -2,7 +2,7 @@ #include "TimerManager.h" #include "WindowManager.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/Check.h" #include "cru/platform/graphics/direct2d/Factory.h" #include "cru/platform/gui/win/Base.h" diff --git a/src/platform/gui/win/Window.cpp b/src/platform/gui/win/Window.cpp index 79ae02e2..47ca93f8 100644 --- a/src/platform/gui/win/Window.cpp +++ b/src/platform/gui/win/Window.cpp @@ -1,7 +1,7 @@ #include "cru/platform/gui/win/Window.h" #include "WindowManager.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/Check.h" #include "cru/platform/graphics/NullPainter.h" #include "cru/platform/gui/Base.h" diff --git a/src/platform/gui/win/WindowManager.h b/src/platform/gui/win/WindowManager.h index afc4a5f5..062f2002 100644 --- a/src/platform/gui/win/WindowManager.h +++ b/src/platform/gui/win/WindowManager.h @@ -1,7 +1,7 @@ #pragma once #include "cru/platform/win/WinPreConfig.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include #include diff --git a/src/ui/ThemeManager.cpp b/src/ui/ThemeManager.cpp index 7358637e..c1b2167e 100644 --- a/src/ui/ThemeManager.cpp +++ b/src/ui/ThemeManager.cpp @@ -1,8 +1,8 @@ #include "cru/ui/ThemeManager.h" #include "Helper.h" -#include "cru/common/StringUtil.h" -#include "cru/common/io/Resource.h" +#include "cru/base/StringUtil.h" +#include "cru/base/io/Resource.h" #include "cru/platform/graphics/Brush.h" #include "cru/platform/graphics/Factory.h" #include "cru/platform/gui/UiApplication.h" diff --git a/src/ui/ThemeResourceDictionary.cpp b/src/ui/ThemeResourceDictionary.cpp index 86a19083..c5986962 100644 --- a/src/ui/ThemeResourceDictionary.cpp +++ b/src/ui/ThemeResourceDictionary.cpp @@ -1,6 +1,6 @@ #include "cru/ui/ThemeResourceDictionary.h" -#include "cru/common/io/CFileStream.h" -#include "cru/common/log/Logger.h" +#include "cru/base/io/CFileStream.h" +#include "cru/base/log/Logger.h" #include "cru/xml/XmlNode.h" #include "cru/xml/XmlParser.h" diff --git a/src/ui/components/Input.cpp b/src/ui/components/Input.cpp index daca68c4..b308ed51 100644 --- a/src/ui/components/Input.cpp +++ b/src/ui/components/Input.cpp @@ -1,7 +1,7 @@ #include "cru/ui/components/Input.h" #include #include -#include "cru/common/StringToNumberConverter.h" +#include "cru/base/StringToNumberConverter.h" #include "cru/ui/controls/Control.h" namespace cru::ui::components { diff --git a/src/ui/controls/Control.cpp b/src/ui/controls/Control.cpp index 3b0d4be3..17633e3d 100644 --- a/src/ui/controls/Control.cpp +++ b/src/ui/controls/Control.cpp @@ -1,6 +1,6 @@ #include "cru/ui/controls/Control.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/gui/Cursor.h" #include "cru/platform/gui/UiApplication.h" #include "cru/ui/host/WindowHost.h" diff --git a/src/ui/controls/RootControl.cpp b/src/ui/controls/RootControl.cpp index 2d23bb36..1bb2e7ee 100644 --- a/src/ui/controls/RootControl.cpp +++ b/src/ui/controls/RootControl.cpp @@ -1,6 +1,6 @@ #include "cru/ui/controls/RootControl.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/gui/Base.h" #include "cru/platform/gui/Window.h" #include "cru/ui/Base.h" diff --git a/src/ui/controls/TextHostControlService.cpp b/src/ui/controls/TextHostControlService.cpp index 36703986..3e885bd3 100644 --- a/src/ui/controls/TextHostControlService.cpp +++ b/src/ui/controls/TextHostControlService.cpp @@ -1,10 +1,10 @@ #include "cru/ui/controls/TextHostControlService.h" #include "../Helper.h" -#include "cru/common/Base.h" -#include "cru/common/String.h" -#include "cru/common/StringUtil.h" -#include "cru/common/log/Logger.h" +#include "cru/base/Base.h" +#include "cru/base/String.h" +#include "cru/base/StringUtil.h" +#include "cru/base/log/Logger.h" #include "cru/platform/graphics/Font.h" #include "cru/platform/gui/Base.h" #include "cru/platform/gui/Clipboard.h" diff --git a/src/ui/document/TextDocumentElement.cpp b/src/ui/document/TextDocumentElement.cpp index ab79823d..1ba39849 100644 --- a/src/ui/document/TextDocumentElement.cpp +++ b/src/ui/document/TextDocumentElement.cpp @@ -1,5 +1,5 @@ #include "cru/ui/document/TextDocumentElement.h" -#include "cru/common/String.h" +#include "cru/base/String.h" #include "cru/ui/document/DocumentElement.h" #include "cru/ui/document/DocumentElementType.h" diff --git a/src/ui/helper/ClickDetector.cpp b/src/ui/helper/ClickDetector.cpp index f76f8af4..de39f14e 100644 --- a/src/ui/helper/ClickDetector.cpp +++ b/src/ui/helper/ClickDetector.cpp @@ -1,6 +1,6 @@ #include "cru/ui/helper/ClickDetector.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/ui/DebugFlags.h" #include "cru/ui/controls/Control.h" #include "cru/ui/host/WindowHost.h" diff --git a/src/ui/helper/ShortcutHub.cpp b/src/ui/helper/ShortcutHub.cpp index 8fbf0b8d..30a563ed 100644 --- a/src/ui/helper/ShortcutHub.cpp +++ b/src/ui/helper/ShortcutHub.cpp @@ -1,6 +1,6 @@ #include "cru/ui/helper/ShortcutHub.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/ui/DebugFlags.h" #include "cru/ui/controls/Control.h" diff --git a/src/ui/host/RoutedEventDispatch.h b/src/ui/host/RoutedEventDispatch.h index 5d1c8ce5..207e1ee6 100644 --- a/src/ui/host/RoutedEventDispatch.h +++ b/src/ui/host/RoutedEventDispatch.h @@ -1,6 +1,6 @@ #pragma once -#include "cru/common/SelfResolvable.h" -#include "cru/common/log/Logger.h" +#include "cru/base/SelfResolvable.h" +#include "cru/base/log/Logger.h" #include "cru/ui/DebugFlags.h" #include "cru/ui/controls/Control.h" #include "cru/ui/host/WindowHost.h" diff --git a/src/ui/host/WindowHost.cpp b/src/ui/host/WindowHost.cpp index 283224b1..616803b6 100644 --- a/src/ui/host/WindowHost.cpp +++ b/src/ui/host/WindowHost.cpp @@ -1,8 +1,8 @@ #include "cru/ui/host/WindowHost.h" #include "RoutedEventDispatch.h" -#include "cru/common/Base.h" -#include "cru/common/log/Logger.h" +#include "cru/base/Base.h" +#include "cru/base/log/Logger.h" #include "cru/platform/graphics/Painter.h" #include "cru/platform/gui/InputMethod.h" #include "cru/platform/gui/UiApplication.h" diff --git a/src/ui/mapper/BorderStyleMapper.cpp b/src/ui/mapper/BorderStyleMapper.cpp index 462a07a1..a51651bd 100644 --- a/src/ui/mapper/BorderStyleMapper.cpp +++ b/src/ui/mapper/BorderStyleMapper.cpp @@ -1,6 +1,6 @@ #include "cru/ui/mapper/BorderStyleMapper.h" #include "../Helper.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/graphics/Brush.h" #include "cru/platform/graphics/Factory.h" #include "cru/ui/mapper/MapperRegistry.h" diff --git a/src/ui/mapper/CursorMapper.cpp b/src/ui/mapper/CursorMapper.cpp index 7de422e8..ed3c91ec 100644 --- a/src/ui/mapper/CursorMapper.cpp +++ b/src/ui/mapper/CursorMapper.cpp @@ -1,6 +1,6 @@ #include "cru/ui/mapper/CursorMapper.h" #include "../Helper.h" -#include "cru/common/Exception.h" +#include "cru/base/Exception.h" #include "cru/platform/gui/Cursor.h" #include "cru/platform/gui/UiApplication.h" diff --git a/src/ui/mapper/style/AndConditionMapper.cpp b/src/ui/mapper/style/AndConditionMapper.cpp index dd8784d5..d57c4927 100644 --- a/src/ui/mapper/style/AndConditionMapper.cpp +++ b/src/ui/mapper/style/AndConditionMapper.cpp @@ -1,5 +1,5 @@ #include "cru/ui/mapper/style/AndConditionMapper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/mapper/style/IConditionMapper.h" #include "cru/ui/style/Condition.h" diff --git a/src/ui/mapper/style/BorderStylerMapper.cpp b/src/ui/mapper/style/BorderStylerMapper.cpp index 95dd28ee..e6e33053 100644 --- a/src/ui/mapper/style/BorderStylerMapper.cpp +++ b/src/ui/mapper/style/BorderStylerMapper.cpp @@ -1,5 +1,5 @@ #include "cru/ui/mapper/style/BorderStylerMapper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/style/ApplyBorderStyleInfo.h" #include "cru/ui/style/Styler.h" diff --git a/src/ui/mapper/style/CheckedConditionMapper.cpp b/src/ui/mapper/style/CheckedConditionMapper.cpp index f61a3d44..74e0a3c5 100644 --- a/src/ui/mapper/style/CheckedConditionMapper.cpp +++ b/src/ui/mapper/style/CheckedConditionMapper.cpp @@ -1,4 +1,4 @@ -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/mapper/style/CheckedConditionMapper.h" #include "cru/ui/style/Condition.h" #include "cru/xml/XmlNode.h" diff --git a/src/ui/mapper/style/ClickStateConditionMapper.cpp b/src/ui/mapper/style/ClickStateConditionMapper.cpp index 5b25de2c..d6b403c9 100644 --- a/src/ui/mapper/style/ClickStateConditionMapper.cpp +++ b/src/ui/mapper/style/ClickStateConditionMapper.cpp @@ -1,6 +1,6 @@ #include "cru/ui/mapper/style/ClickStateConditionMapper.h" -#include "cru/common/ClonablePtr.h" -#include "cru/common/Exception.h" +#include "cru/base/ClonablePtr.h" +#include "cru/base/Exception.h" #include "cru/ui/helper/ClickDetector.h" #include "cru/ui/style/Condition.h" diff --git a/src/ui/mapper/style/ContentBrushStylerMapper.cpp b/src/ui/mapper/style/ContentBrushStylerMapper.cpp index e83f4988..b3571374 100644 --- a/src/ui/mapper/style/ContentBrushStylerMapper.cpp +++ b/src/ui/mapper/style/ContentBrushStylerMapper.cpp @@ -1,5 +1,5 @@ #include "cru/ui/mapper/style/ContentBrushStylerMapper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/platform/graphics/Brush.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/style/Styler.h" diff --git a/src/ui/mapper/style/CursorStylerMapper.cpp b/src/ui/mapper/style/CursorStylerMapper.cpp index 6798798c..3b060c25 100644 --- a/src/ui/mapper/style/CursorStylerMapper.cpp +++ b/src/ui/mapper/style/CursorStylerMapper.cpp @@ -1,5 +1,5 @@ #include "cru/ui/mapper/style/CursorStylerMapper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/platform/gui/Cursor.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/style/Styler.h" diff --git a/src/ui/mapper/style/FocusConditionMapper.cpp b/src/ui/mapper/style/FocusConditionMapper.cpp index b9e89e2e..dfefb921 100644 --- a/src/ui/mapper/style/FocusConditionMapper.cpp +++ b/src/ui/mapper/style/FocusConditionMapper.cpp @@ -1,4 +1,4 @@ -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/mapper/style/FocusConditionMapper.h" #include "cru/ui/style/Condition.h" #include "cru/xml/XmlNode.h" diff --git a/src/ui/mapper/style/FontStylerMapper.cpp b/src/ui/mapper/style/FontStylerMapper.cpp index 884832ee..3b1817ac 100644 --- a/src/ui/mapper/style/FontStylerMapper.cpp +++ b/src/ui/mapper/style/FontStylerMapper.cpp @@ -1,5 +1,5 @@ #include "cru/ui/mapper/style/FontStylerMapper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/mapper/MapperRegistry.h" namespace cru::ui::mapper::style { diff --git a/src/ui/mapper/style/HoverConditionMapper.cpp b/src/ui/mapper/style/HoverConditionMapper.cpp index 97767b14..0110edd9 100644 --- a/src/ui/mapper/style/HoverConditionMapper.cpp +++ b/src/ui/mapper/style/HoverConditionMapper.cpp @@ -1,5 +1,5 @@ #include "cru/ui/mapper/style/HoverConditionMapper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/style/Condition.h" namespace cru::ui::mapper::style { diff --git a/src/ui/mapper/style/NoConditionMapper.cpp b/src/ui/mapper/style/NoConditionMapper.cpp index 397162f1..a36e70d2 100644 --- a/src/ui/mapper/style/NoConditionMapper.cpp +++ b/src/ui/mapper/style/NoConditionMapper.cpp @@ -1,5 +1,5 @@ #include "cru/ui/mapper/style/NoConditionMapper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/xml/XmlNode.h" namespace cru::ui::mapper::style { diff --git a/src/ui/mapper/style/OrConditionMapper.cpp b/src/ui/mapper/style/OrConditionMapper.cpp index 7b932dbc..521c57ae 100644 --- a/src/ui/mapper/style/OrConditionMapper.cpp +++ b/src/ui/mapper/style/OrConditionMapper.cpp @@ -1,5 +1,5 @@ #include "cru/ui/mapper/style/OrConditionMapper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/mapper/style/IConditionMapper.h" #include "cru/ui/style/Condition.h" diff --git a/src/ui/mapper/style/StyleRuleMapper.cpp b/src/ui/mapper/style/StyleRuleMapper.cpp index 2ab13c90..2eb5b0a2 100644 --- a/src/ui/mapper/style/StyleRuleMapper.cpp +++ b/src/ui/mapper/style/StyleRuleMapper.cpp @@ -1,7 +1,7 @@ #include "cru/ui/mapper/style/StyleRuleMapper.h" -#include "cru/common/ClonablePtr.h" -#include "cru/common/Exception.h" -#include "cru/common/log/Logger.h" +#include "cru/base/ClonablePtr.h" +#include "cru/base/Exception.h" +#include "cru/base/log/Logger.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/mapper/style/IConditionMapper.h" #include "cru/ui/mapper/style/IStylerMapper.h" diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp index 1392af1e..81a1aa60 100644 --- a/src/ui/render/BorderRenderObject.cpp +++ b/src/ui/render/BorderRenderObject.cpp @@ -1,7 +1,7 @@ #include "cru/ui/render/BorderRenderObject.h" #include "../Helper.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/graphics/Factory.h" #include "cru/platform/graphics/Geometry.h" #include "cru/platform/graphics/Painter.h" diff --git a/src/ui/render/FlexLayoutRenderObject.cpp b/src/ui/render/FlexLayoutRenderObject.cpp index 988e7590..7bbf9d57 100644 --- a/src/ui/render/FlexLayoutRenderObject.cpp +++ b/src/ui/render/FlexLayoutRenderObject.cpp @@ -1,6 +1,6 @@ #include "cru/ui/render/FlexLayoutRenderObject.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/ui/render/LayoutHelper.h" #include diff --git a/src/ui/render/LayoutHelper.cpp b/src/ui/render/LayoutHelper.cpp index a9121321..bbd3c116 100644 --- a/src/ui/render/LayoutHelper.cpp +++ b/src/ui/render/LayoutHelper.cpp @@ -1,6 +1,6 @@ #include "cru/ui/render/LayoutHelper.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" namespace cru::ui::render { float CalculateAnchorByAlignment(Alignment alignment, float start_point, diff --git a/src/ui/render/RenderObject.cpp b/src/ui/render/RenderObject.cpp index a370f749..64411036 100644 --- a/src/ui/render/RenderObject.cpp +++ b/src/ui/render/RenderObject.cpp @@ -1,7 +1,7 @@ #include "cru/ui/render/RenderObject.h" -#include "cru/common/Exception.h" -#include "cru/common/log/Logger.h" +#include "cru/base/Exception.h" +#include "cru/base/log/Logger.h" #include "cru/platform/GraphicsBase.h" #include "cru/ui/DebugFlags.h" #include "cru/ui/controls/Control.h" diff --git a/src/ui/render/ScrollBar.cpp b/src/ui/render/ScrollBar.cpp index 3e578d37..326f7504 100644 --- a/src/ui/render/ScrollBar.cpp +++ b/src/ui/render/ScrollBar.cpp @@ -1,7 +1,7 @@ #include "cru/ui/render/ScrollBar.h" #include "../Helper.h" -#include "cru/common/Base.h" +#include "cru/base/Base.h" #include "cru/platform/GraphicsBase.h" #include "cru/platform/graphics/Factory.h" #include "cru/platform/graphics/Geometry.h" diff --git a/src/ui/render/StackLayoutRenderObject.cpp b/src/ui/render/StackLayoutRenderObject.cpp index 9ca9bf02..d71c5749 100644 --- a/src/ui/render/StackLayoutRenderObject.cpp +++ b/src/ui/render/StackLayoutRenderObject.cpp @@ -1,6 +1,6 @@ #include "cru/ui/render/StackLayoutRenderObject.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/ui/render/LayoutHelper.h" #include "cru/ui/render/MeasureRequirement.h" diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp index 135c2d02..14e45080 100644 --- a/src/ui/render/TextRenderObject.cpp +++ b/src/ui/render/TextRenderObject.cpp @@ -1,7 +1,7 @@ #include "cru/ui/render/TextRenderObject.h" #include "../Helper.h" -#include "cru/common/log/Logger.h" +#include "cru/base/log/Logger.h" #include "cru/platform/graphics/Factory.h" #include "cru/platform/graphics/Painter.h" #include "cru/platform/graphics/TextLayout.h" diff --git a/src/ui/style/Condition.cpp b/src/ui/style/Condition.cpp index f7cdf7fd..a0de03dc 100644 --- a/src/ui/style/Condition.cpp +++ b/src/ui/style/Condition.cpp @@ -1,8 +1,8 @@ #include "cru/ui/style/Condition.h" #include -#include "cru/common/ClonablePtr.h" -#include "cru/common/Event.h" +#include "cru/base/ClonablePtr.h" +#include "cru/base/Event.h" #include "cru/ui/controls/Control.h" #include "cru/ui/controls/ICheckableControl.h" #include "cru/ui/controls/IClickableControl.h" diff --git a/src/ui/style/StyleRuleSet.cpp b/src/ui/style/StyleRuleSet.cpp index 7b6454ec..ab3a2d01 100644 --- a/src/ui/style/StyleRuleSet.cpp +++ b/src/ui/style/StyleRuleSet.cpp @@ -1,5 +1,5 @@ #include "cru/ui/style/StyleRuleSet.h" -#include "cru/common/Event.h" +#include "cru/base/Event.h" #include "cru/ui/controls/Control.h" #include "cru/ui/model/IListChangeNotify.h" diff --git a/src/ui/style/Styler.cpp b/src/ui/style/Styler.cpp index 3d7ff1f9..a4e3ac25 100644 --- a/src/ui/style/Styler.cpp +++ b/src/ui/style/Styler.cpp @@ -1,7 +1,7 @@ #include "cru/ui/style/Styler.h" #include "../Helper.h" -#include "cru/common/ClonablePtr.h" +#include "cru/base/ClonablePtr.h" #include "cru/platform/gui/Cursor.h" #include "cru/platform/gui/UiApplication.h" #include "cru/ui/controls/Control.h" diff --git a/test/common/Event2Test.cpp b/test/common/Event2Test.cpp index 0d3222cc..0c67f28e 100644 --- a/test/common/Event2Test.cpp +++ b/test/common/Event2Test.cpp @@ -1,4 +1,4 @@ -#include "cru/common/Event2.h" +#include "cru/base/Event2.h" #include diff --git a/test/common/HandlerRegistryTest.cpp b/test/common/HandlerRegistryTest.cpp index 03e190e3..aacef70f 100644 --- a/test/common/HandlerRegistryTest.cpp +++ b/test/common/HandlerRegistryTest.cpp @@ -1,4 +1,4 @@ -#include "cru/common/HandlerRegistry.h" +#include "cru/base/HandlerRegistry.h" #include diff --git a/test/common/PropertyTreeTest.cpp b/test/common/PropertyTreeTest.cpp index a14fe924..24d7ca9e 100644 --- a/test/common/PropertyTreeTest.cpp +++ b/test/common/PropertyTreeTest.cpp @@ -1,4 +1,4 @@ -#include "cru/common/PropertyTree.h" +#include "cru/base/PropertyTree.h" #include diff --git a/test/common/SelfResolvableTest.cpp b/test/common/SelfResolvableTest.cpp index 36b8cd6f..c214bd77 100644 --- a/test/common/SelfResolvableTest.cpp +++ b/test/common/SelfResolvableTest.cpp @@ -1,5 +1,5 @@ -#include "cru/common/Base.h" -#include "cru/common/SelfResolvable.h" +#include "cru/base/Base.h" +#include "cru/base/SelfResolvable.h" #include diff --git a/test/common/StringTest.cpp b/test/common/StringTest.cpp index adbd5598..9ed351e5 100644 --- a/test/common/StringTest.cpp +++ b/test/common/StringTest.cpp @@ -1,5 +1,5 @@ -#include "cru/common/Format.h" -#include "cru/common/String.h" +#include "cru/base/Format.h" +#include "cru/base/String.h" #include diff --git a/test/common/StringToNumberConverterTest.cpp b/test/common/StringToNumberConverterTest.cpp index d4bb36f4..82062bdb 100644 --- a/test/common/StringToNumberConverterTest.cpp +++ b/test/common/StringToNumberConverterTest.cpp @@ -1,5 +1,5 @@ -#include "cru/common/Exception.h" -#include "cru/common/StringToNumberConverter.h" +#include "cru/base/Exception.h" +#include "cru/base/StringToNumberConverter.h" #include diff --git a/test/common/StringUtilTest.cpp b/test/common/StringUtilTest.cpp index 613243c5..1da6e963 100644 --- a/test/common/StringUtilTest.cpp +++ b/test/common/StringUtilTest.cpp @@ -1,5 +1,5 @@ -#include "cru/common/String.h" -#include "cru/common/StringUtil.h" +#include "cru/base/String.h" +#include "cru/base/StringUtil.h" #include diff --git a/test/common/SubProcessTest.cpp b/test/common/SubProcessTest.cpp index 03f9d221..d353dec0 100644 --- a/test/common/SubProcessTest.cpp +++ b/test/common/SubProcessTest.cpp @@ -1,5 +1,5 @@ -#include "cru/common/String.h" -#include "cru/common/SubProcess.h" +#include "cru/base/String.h" +#include "cru/base/SubProcess.h" #include diff --git a/test/common/platform/unix/UnixFileStreamTest.cpp b/test/common/platform/unix/UnixFileStreamTest.cpp index 0f9d9834..fa99aa29 100644 --- a/test/common/platform/unix/UnixFileStreamTest.cpp +++ b/test/common/platform/unix/UnixFileStreamTest.cpp @@ -1,4 +1,4 @@ -#include "cru/common/platform/unix/UnixFileStream.h" +#include "cru/base/platform/unix/UnixFileStream.h" #include diff --git a/test/common/platform/win/StreamConvertTest.cpp b/test/common/platform/win/StreamConvertTest.cpp index f49d18dc..90ebb568 100644 --- a/test/common/platform/win/StreamConvertTest.cpp +++ b/test/common/platform/win/StreamConvertTest.cpp @@ -1,7 +1,7 @@ -#include "cru/common/io/OpenFileFlag.h" -#include "cru/common/platform/win/Exception.h" -#include "cru/common/platform/win/StreamConvert.h" -#include "cru/common/platform/win/Win32FileStream.h" +#include "cru/base/io/OpenFileFlag.h" +#include "cru/base/platform/win/Exception.h" +#include "cru/base/platform/win/StreamConvert.h" +#include "cru/base/platform/win/Win32FileStream.h" #include diff --git a/test/common/platform/win/Win32FileStreamTest.cpp b/test/common/platform/win/Win32FileStreamTest.cpp index d5de451b..dc2f49d4 100644 --- a/test/common/platform/win/Win32FileStreamTest.cpp +++ b/test/common/platform/win/Win32FileStreamTest.cpp @@ -1,5 +1,5 @@ -#include "cru/common/io/OpenFileFlag.h" -#include "cru/common/platform/win/Win32FileStream.h" +#include "cru/base/io/OpenFileFlag.h" +#include "cru/base/platform/win/Win32FileStream.h" #include -- cgit v1.2.3