Compare commits

..

5 Commits

Author SHA1 Message Date
jeanlemotan 7d21ffa1ee Work around a bug in fast_io 2024-09-08 16:09:16 +02:00
catalinvasile 259fe53aff Fixed compile error 2024-09-05 17:08:23 +02:00
catalinvasile 56c367a3c4 Added embedded libzip
Prefixed all libzip zip_ funcs to fs_zip_ to avoid clashes and link errors due to assimp
Zip pack and zip writer work with libzip now
2024-07-16 12:57:03 +02:00
catalinvasile 5ec1fddf57 Fixed crash on enumerate + rvalue 2024-07-11 17:57:31 +02:00
catalinvasile 28b74b4056 Using PathView to pass paths to APIs 2024-07-10 13:31:12 +02:00
634 changed files with 116812 additions and 1609 deletions
+3 -2
View File
@@ -50,7 +50,7 @@ if(NOT TARGET zlib)
endif()
endif()
file(GLOB_RECURSE SRC "src/*.cpp")
file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c" "src/*.h")
file(GLOB_RECURSE HEADERS "include/*.h" "include/*.inl")
foreach(_source IN ITEMS ${HEADERS})
@@ -70,9 +70,10 @@ endforeach()
add_library(FS STATIC ${SRC} ${HEADERS})
target_include_directories(FS PUBLIC "include")
target_include_directories(FS PRIVATE "src")
target_include_directories(FS PRIVATE "src/libzip")
target_include_directories(FS PUBLIC "${PROJECT_SOURCE_DIR}/../Logger/include")
target_include_directories(FS PUBLIC "${PROJECT_SOURCE_DIR}/../cppcoro/include")
target_include_directories(FS PUBLIC "${PROJECT_SOURCE_DIR}/../fast_io/include")
target_include_directories(FS PRIVATE "src/fast_io/include")
target_link_libraries(FS TL)
target_link_libraries(FS zlib)
+6 -4
View File
@@ -14,9 +14,9 @@ template<typename parse_separators, typename format_separator>
struct WindowsSystemCustom : public tl::detail::path_system::base_path_system<parse_separators, format_separator>
{
template<typename T>
static T format_absolute(const tl::vector<tl::string>& members);
static void parse_absolute(tl::vector<tl::string>& o_elements, const char* path, size_t size);
static bool validate_abs_path(const tl::vector<tl::string>& members);
static T format_abs(tl::span<const tl::string> members);
static void parse_abs(tl::vector<tl::string>& o_elements, const char* path, size_t size);
static bool validate_abs_path(tl::span<const tl::string> members);
static bool match(const char* path, size_t size);
};
TL_DECLARE_STRING_VECTOR(WindowsParseSeparators, "\\", "/");
@@ -36,7 +36,9 @@ TL_DECLARE_STRING_LITERAL(UncFormatSeparator, "\\");
using UncSystem = tl::simple_path_system<UncRootTag, UncParseSeparators, UncFormatSeparator>;
using AbsPath = tl::abs_path<tl::path_systems<WindowsSystem, PosixSystem, UncSystem>>;
using AbsPathView = AbsPath::path_view_type;
using RelPath = AbsPath::rel_path_type;
using RelPathView = RelPath::path_view_type;
}
@@ -48,6 +50,6 @@ struct std::formatter<fs::RelPath>
constexpr auto parse(format_parse_context& ctx) noexcept { return ctx.begin(); }
auto format(const fs::RelPath& p, std::format_context& ctx) const
{
return format_to(ctx.out(), "{}", p.get_as<fs::PosixSystem>());
return format_to(ctx.out(), "{}", p.str<fs::PosixSystem>());
}
};
+5 -5
View File
@@ -12,16 +12,16 @@ namespace detail
// windows path system
template<typename parse_separators, typename format_separator>
template<typename T>
T WindowsSystemCustom<parse_separators, format_separator>::format_absolute(const tl::vector<tl::string>& members)
T WindowsSystemCustom<parse_separators, format_separator>::format_abs(tl::span<const tl::string> members)
{
return tl::simple_path_system<detail::EmptyRootTag, parse_separators, format_separator>::template format_absolute<T>(members);
return tl::simple_path_system<detail::EmptyRootTag, parse_separators, format_separator>::template format_abs<T>(members);
}
template<typename parse_separators, typename format_separator>
void WindowsSystemCustom<parse_separators, format_separator>::parse_absolute(tl::vector<tl::string>& o_elements, const char* path, size_t size)
void WindowsSystemCustom<parse_separators, format_separator>::parse_abs(tl::vector<tl::string>& o_elements, const char* path, size_t size)
{
// On windows, the drive letter case is undefined. To avoid issues (hashing, etc), we always convert the drive letter to uppercase
tl::simple_path_system<detail::EmptyRootTag, parse_separators, format_separator>::parse_absolute(o_elements, path, size);
tl::simple_path_system<detail::EmptyRootTag, parse_separators, format_separator>::parse_abs(o_elements, path, size);
if (!o_elements.empty())
{
tl::string& str = o_elements.front();
@@ -42,7 +42,7 @@ namespace detail
}
template<typename parse_separators, typename format_separator>
bool WindowsSystemCustom<parse_separators, format_separator>::validate_abs_path(const tl::vector<tl::string>& members)
bool WindowsSystemCustom<parse_separators, format_separator>::validate_abs_path(tl::span<const tl::string> members)
{
return !members.empty() && match(members[0].c_str(), members[0].size());
}
+2 -2
View File
@@ -15,11 +15,11 @@ FS_API uint64_t computeCRC64(uint64_t crc, tl::span<const uint8_t> data);
typedef tl::result<uint32_t, Error> CRC32StreamResult;
FS_API CRC32StreamResult crc32Stream(IStreamSource& source, uint32_t crc = 0, size_t bufferSize = 0);
FS_API CRC32StreamResult crc32File(const IFilesystem& filesystem, const AbsPath& filePath, uint32_t crc = 0, size_t bufferSize = 0);
FS_API CRC32StreamResult crc32File(const IFilesystem& filesystem, AbsPathView filePath, uint32_t crc = 0, size_t bufferSize = 0);
typedef tl::result<uint64_t, Error> CRC64StreamResult;
FS_API CRC64StreamResult crc64Stream(IStreamSource& source, uint64_t crc = 0, size_t bufferSize = 0);
FS_API CRC64StreamResult crc64File(const IFilesystem& filesystem, const AbsPath& filePath, uint64_t crc = 0, size_t bufferSize = 0);
FS_API CRC64StreamResult crc64File(const IFilesystem& filesystem, AbsPathView filePath, uint64_t crc = 0, size_t bufferSize = 0);
//////////////////////////////////////////////////////////////////////////
}
+3 -3
View File
@@ -16,9 +16,9 @@ class IFilesystem;
using CopyStreamResult = tl::result<uint64_t, Error>;
FS_API CopyStreamResult copyStream(IStreamSink& sink, IStreamSource& source, size_t bufferSize = 0);
FS_API CopyStreamResult copyStream(IStreamSink& sink, IStreamSource& source, const ProcessDataCallback& dataCallback, size_t bufferSize = 0);
FS_API CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, const AbsPath& filePath, size_t bufferSize = 0);
FS_API CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, const AbsPath& filePath, const ProcessDataCallback& dataCallback, size_t bufferSize = 0);
FS_API CopyStreamResult copyFile(IFilesystem& dstFilesystem, const AbsPath& dstFilePath, const IFilesystem& srcFilesystem, const AbsPath& srcFilePath, size_t bufferSize = 0);
FS_API CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, AbsPathView filePath, size_t bufferSize = 0);
FS_API CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, AbsPathView filePath, const ProcessDataCallback& dataCallback, size_t bufferSize = 0);
FS_API CopyStreamResult copyFile(IFilesystem& dstFilesystem, AbsPathView dstFilePath, const IFilesystem& srcFilesystem, AbsPathView srcFilePath, size_t bufferSize = 0);
//////////////////////////////////////////////////////////////////////////
}
+25 -25
View File
@@ -25,8 +25,8 @@ public:
TL_DECLARE_INTEGRAL_ID(PackId, uint64_t)
tl::result<PackId> mountFront(AbsPath mountPoint, tl::unique_ref<IPack> pack);
tl::result<PackId> mountBack(AbsPath mountPoint, tl::unique_ref<IPack> pack);
tl::result<PackId> mountFront(AbsPathView mountPoint, tl::unique_ref<IPack> pack);
tl::result<PackId> mountBack(AbsPathView mountPoint, tl::unique_ref<IPack> pack);
//unmounts all the packs for this point. It basically deletes the mount point
cppcoro::generator<tl::unique_ref<IPack>> unmountAll();
@@ -35,37 +35,37 @@ public:
tl::unique_ptr<IPack> unmount(PackId packId);
//Returns the physical location of the virtual pack.
ConvertToNativePathResult convertToNativePath(const AbsPath& path) const override;
ConvertToNativePathResult convertToNativePath(AbsPathView path) const override;
OpenSourceResult openSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const override;
OpenStreamSourceResult openStreamSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const override;
OpenMapSourceResult openMapSource(const AbsPath& path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override;
OpenSinkResult openSink(const AbsPath& path, Mode mode, SinkFlags flags = SinkFlags()) override;
OpenStreamSinkResult openStreamSink(const AbsPath& path, Mode mode, SinkFlags flags = SinkFlags()) override;
OpenMapSinkResult openMapSink(const AbsPath& path, Mode mode, size_t size, SinkFlags flags = SinkFlags()) override;
OpenSourceResult openSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
OpenStreamSourceResult openStreamSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
OpenMapSourceResult openMapSource(AbsPathView path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override;
OpenSinkResult openSink(AbsPathView path, Mode mode, SinkFlags flags = SinkFlags()) override;
OpenStreamSinkResult openStreamSink(AbsPathView path, Mode mode, SinkFlags flags = SinkFlags()) override;
OpenMapSinkResult openMapSink(AbsPathView path, Mode mode, size_t size, SinkFlags flags = SinkFlags()) override;
IsFileResult isFile(const AbsPath& path) const override;
IsFolderResult isFolder(const AbsPath& path) const override;
ExistsResult exists(const AbsPath& path) const override;
IsFileResult isFile(AbsPathView path) const override;
IsFolderResult isFolder(AbsPathView path) const override;
ExistsResult exists(AbsPathView path) const override;
MakeFolderResult makeFolder(const AbsPath& path) override;
MakeFolderResult makeFolder(AbsPathView path) override;
RenameResult rename(const AbsPath& path, const AbsPath& newPath) override;
RenameResult rename(AbsPathView path, AbsPathView newPath) override;
RemoveResult remove(const AbsPath& path) override;
RemoveRecursivelyResult removeRecursively(const AbsPath& path) override;
RemoveResult remove(AbsPathView path) override;
RemoveRecursivelyResult removeRecursively(AbsPathView path) override;
CopyResult copy(const AbsPath& path, const AbsPath& newPath) override;
CopyResult copy(AbsPathView path, AbsPathView newPath) override;
MakeHardLinkResult makeHardLink(const AbsPath& sourcePath, const AbsPath& linkPath) override;
MakeSoftLinkResult makeSymLink(const AbsPath& sourcePath, const AbsPath& linkPath) override;
MakeHardLinkResult makeHardLink(AbsPathView sourcePath, AbsPathView linkPath) override;
MakeSoftLinkResult makeSymLink(AbsPathView sourcePath, AbsPathView linkPath) override;
SetWriteTimeResult setWriteTime(const AbsPath& path, time_t time) override;
SetWriteTimeResult setWriteTime(AbsPathView path, time_t time) override;
GetStatResult getStat(const AbsPath& path) const override;
GetStatResult getStat(AbsPathView path) const override;
cppcoro::generator<EnumerateEntry> enumerate(const AbsPath& path) const override;
cppcoro::generator<EnumerateEntry> enumerateRecursively(const AbsPath& path) const override;
cppcoro::generator<EnumerateEntry> enumerate(AbsPath path) const override;
cppcoro::generator<EnumerateEntry> enumerateRecursively(AbsPath path) const override;
private:
struct PackData
@@ -86,14 +86,14 @@ private:
};
tl::vector<PackData> m_packsData;
void convertToPackPath(AbsPath& packPath, const AbsPath& path, const AbsPath& mountPoint) const;
void convertToPackPath(AbsPath& packPath, AbsPathView path, AbsPathView mountPoint) const;
enum class MountPolicy
{
Front, //the pack will be mounted over packs from the same mount point. This pack will take precedence
Back //the pack will be at the bottom of existing packs from the same mount point. Its streams will be searched last
};
tl::result<PackId> mount(AbsPath mountPoint, tl::unique_ref<IPack> pack, MountPolicy policy);
tl::result<PackId> mount(AbsPathView mountPoint, tl::unique_ref<IPack> pack, MountPolicy policy);
};
+1 -1
View File
@@ -16,7 +16,7 @@ class FS_API FileMapSink final : public IMapSink
{
friend class NativeFilesystem;
public:
FileMapSink(const AbsPath& filepath, size_t size, Mode mode = Mode::CreateOrOpenAndClear, Flags flags = Flags());
FileMapSink(AbsPathView filepath, size_t size, Mode mode = Mode::CreateOrOpenAndClear, Flags flags = Flags());
~FileMapSink() override;
bool isValid() const;
+2 -2
View File
@@ -15,8 +15,8 @@ class FS_API FileMapSource final : public IMapSource
{
friend class NativeFilesystem;
public:
explicit FileMapSource(const AbsPath& filepath);
FileMapSource(const AbsPath& filepath, uint64_t start, size_t size);
explicit FileMapSource(AbsPathView filepath);
FileMapSource(AbsPathView filepath, uint64_t start, size_t size);
~FileMapSource() override;
+1 -1
View File
@@ -12,7 +12,7 @@ namespace fs
class FS_API FileSink final : public ISink
{
public:
FileSink(const AbsPath& filepath, Mode mode, Flags flags = Flags()) noexcept;
FileSink(AbsPathView filepath, Mode mode, Flags flags = Flags()) noexcept;
~FileSink() noexcept override;
FileSink(FileSink&& other) noexcept;
+2 -2
View File
@@ -10,8 +10,8 @@ namespace fs
class FS_API FileSource final : public ISource
{
public:
explicit FileSource(const AbsPath& i_filepath) noexcept;
FileSource(const AbsPath& i_filepath, Flags i_flags) noexcept;
explicit FileSource(AbsPathView i_filepath) noexcept;
FileSource(AbsPathView i_filepath, Flags i_flags) noexcept;
~FileSource() noexcept override;
FileSource(FileSource&& i_other) noexcept;
+13 -13
View File
@@ -10,28 +10,28 @@ namespace fs
class FS_API FolderPack : virtual public IPack
{
public:
explicit FolderPack(AbsPath location);
FolderPack(tl::lent_ref<IFilesystem> filesystem, AbsPath location);
explicit FolderPack(AbsPathView location);
FolderPack(tl::lent_ref<IFilesystem> filesystem, AbsPathView location);
~FolderPack() override = default;
OpenSourceResult openSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const override;
OpenStreamSourceResult openStreamSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const override;
OpenMapSourceResult openMapSource(const AbsPath& path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override;
OpenSourceResult openSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
OpenStreamSourceResult openStreamSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
OpenMapSourceResult openMapSource(AbsPathView path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override;
IsFileResult isFile(const AbsPath& path) const override;
IsFolderResult isFolder(const AbsPath& path) const override;
ExistsResult exists(const AbsPath& path) const override;
IsFileResult isFile(AbsPathView path) const override;
IsFolderResult isFolder(AbsPathView path) const override;
ExistsResult exists(AbsPathView path) const override;
GetStatResult getStat(const AbsPath& path) const override;
GetStatResult getStat(AbsPathView path) const override;
cppcoro::generator<EnumerateEntry> enumerate(const AbsPath& path) const override;
cppcoro::generator<EnumerateEntry> enumerateRecursively(const AbsPath& path) const override;
cppcoro::generator<EnumerateEntry> enumerate(AbsPath path) const override;
cppcoro::generator<EnumerateEntry> enumerateRecursively(AbsPath path) const override;
ConvertToNativePathResult convertToNativePath(const AbsPath& path) const override;
ConvertToNativePathResult convertToNativePath(AbsPathView path) const override;
protected:
AbsPath convertToUnderlyingPath(const AbsPath& path) const;
AbsPath convertToUnderlyingPath(AbsPathView path) const;
tl::lent_ref<IFilesystem> m_filesystem;
AbsPath m_location;
};
+26 -22
View File
@@ -44,7 +44,7 @@ using SetWriteTimeResult = tl::result<void, Error>;
struct EnumerateEntry
{
RelPath path;
RelPathView path;
bool isFolder = false;
};
@@ -68,9 +68,9 @@ public:
//Opens a Read-only Stream
//Searches for the stream in the packs from the mountpoint in top to bottom order, and opens if found
virtual OpenSourceResult openSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const = 0;
virtual OpenStreamSourceResult openStreamSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const = 0;
virtual OpenMapSourceResult openMapSource(const AbsPath& path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const = 0;
virtual OpenSourceResult openSource(AbsPathView path, SourceFlags flags = SourceFlags()) const = 0;
virtual OpenStreamSourceResult openStreamSource(AbsPathView path, SourceFlags flags = SourceFlags()) const = 0;
virtual OpenMapSourceResult openMapSource(AbsPathView path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const = 0;
using SinkFlag = ISink::Flag;
using SinkFlags = ISink::Flags;
@@ -79,46 +79,50 @@ public:
//Searches for the stream in the packs from the mountpoint in top to bottom order, and opens if found.
//If used with the CREATE flag, it will create the stream if not found.
//NOTE: this will fail if the mountpoint has only read-only packs (zip files, etc)
virtual OpenSinkResult openSink(const AbsPath& path, Mode mode, SinkFlags flags = SinkFlags()) = 0;
virtual OpenStreamSinkResult openStreamSink(const AbsPath& path, Mode mode, SinkFlags flags = SinkFlags()) = 0;
virtual OpenMapSinkResult openMapSink(const AbsPath& path, Mode mode, size_t size, SinkFlags flags = SinkFlags()) = 0;
virtual OpenSinkResult openSink(AbsPathView path, Mode mode, SinkFlags flags = SinkFlags()) = 0;
virtual OpenStreamSinkResult openStreamSink(AbsPathView path, Mode mode, SinkFlags flags = SinkFlags()) = 0;
virtual OpenMapSinkResult openMapSink(AbsPathView path, Mode mode, size_t size, SinkFlags flags = SinkFlags()) = 0;
//////////////////////////////////////////////////////////////////////////
//Returns the physical location of the virtual pack.
virtual ConvertToNativePathResult convertToNativePath(const AbsPath& path) const = 0;
virtual ConvertToNativePathResult convertToNativePath(AbsPathView path) const = 0;
virtual IsFileResult isFile(const AbsPath& path) const = 0;
virtual IsFolderResult isFolder(const AbsPath& path) const = 0;
virtual ExistsResult exists(const AbsPath& path) const = 0;
virtual IsFileResult isFile(AbsPathView path) const = 0;
virtual IsFolderResult isFolder(AbsPathView path) const = 0;
virtual ExistsResult exists(AbsPathView path) const = 0;
virtual GetStatResult getStat(const AbsPath& path) const = 0;
virtual GetStatResult getStat(AbsPathView path) const = 0;
virtual MakeFolderResult makeFolder(const AbsPath& path) = 0;
virtual MakeFolderResult makeFolder(AbsPathView path) = 0;
virtual RenameResult rename(const AbsPath& path, const AbsPath& newPath) = 0;
virtual RenameResult rename(AbsPathView path, AbsPathView newPath) = 0;
//this removes one file or one folder. The folder is removed ONLY if it's empty. If you want to remove a non-empty folder, use RemoveRecursively
virtual RemoveResult remove(const AbsPath& path) = 0;
virtual RemoveResult remove(AbsPathView path) = 0;
virtual CopyResult copy(const AbsPath& path, const AbsPath& newPath) = 0;
virtual CopyResult copy(AbsPathView path, AbsPathView newPath) = 0;
// Hard links are essentially a new name for the same file data.
// The file becomes reference counted and the data will be deleted when all handles to it are removed from the FS.
virtual MakeHardLinkResult makeHardLink(const AbsPath& sourcePath, const AbsPath& linkPath) = 0;
virtual MakeHardLinkResult makeHardLink(AbsPathView sourcePath, AbsPathView linkPath) = 0;
// Soft links are like 'weak' pointers to a file. If the original gets deleted the soft link becomes 'null'.
virtual MakeSoftLinkResult makeSymLink(const AbsPath& sourcePath, const AbsPath& linkPath) = 0;
virtual MakeSoftLinkResult makeSymLink(AbsPathView sourcePath, AbsPathView linkPath) = 0;
//Use this function in order to remove the set folder and all of the files and folders contained inside.
//This function is not atomic; if the removal of any of the folders or files fails, the process will be stopped
//and the function will return false, but any of the previously removed files will be already removed.
virtual RemoveRecursivelyResult removeRecursively(const AbsPath& path) = 0;
virtual RemoveRecursivelyResult removeRecursively(AbsPathView path) = 0;
virtual SetWriteTimeResult setWriteTime(const AbsPath& path, time_t time) = 0;
virtual SetWriteTimeResult setWriteTime(AbsPathView path, time_t time) = 0;
virtual cppcoro::generator<EnumerateEntry> enumerate(const AbsPath& path) const = 0;
virtual cppcoro::generator<EnumerateEntry> enumerateRecursively(const AbsPath& path) const = 0;
//The AbsPath is a copy, because there are lifetime subtleties when using coroutines.
//In particular, without pass-by-value, this would crash because nobody is storing the rvalue:
// for (auto e: fs.enumerate(path + "other folder"))
// {}
virtual cppcoro::generator<EnumerateEntry> enumerate(AbsPath path) const = 0;
virtual cppcoro::generator<EnumerateEntry> enumerateRecursively(AbsPath path) const = 0;
};
+10 -10
View File
@@ -23,20 +23,20 @@ public:
using SourceFlags = IFilesystem::SourceFlags;
using MapView = IFilesystem::MapView;
virtual OpenSourceResult openSource(const AbsPath& i_path, SourceFlags i_flags = SourceFlags()) const = 0;
virtual OpenStreamSourceResult openStreamSource(const AbsPath& i_path, SourceFlags i_flags = SourceFlags()) const = 0;
virtual OpenMapSourceResult openMapSource(const AbsPath& i_path, MapView i_mapView = MapView(), SourceFlags i_flags = SourceFlags()) const = 0;
virtual OpenSourceResult openSource(AbsPathView i_path, SourceFlags i_flags = SourceFlags()) const = 0;
virtual OpenStreamSourceResult openStreamSource(AbsPathView i_path, SourceFlags i_flags = SourceFlags()) const = 0;
virtual OpenMapSourceResult openMapSource(AbsPathView i_path, MapView i_mapView = MapView(), SourceFlags i_flags = SourceFlags()) const = 0;
virtual IsFileResult isFile(const AbsPath& i_path) const = 0;
virtual IsFolderResult isFolder(const AbsPath& i_path) const = 0;
virtual ExistsResult exists(const AbsPath& i_path) const = 0;
virtual IsFileResult isFile(AbsPathView i_path) const = 0;
virtual IsFolderResult isFolder(AbsPathView i_path) const = 0;
virtual ExistsResult exists(AbsPathView i_path) const = 0;
virtual GetStatResult getStat(const AbsPath& i_path) const = 0;
virtual GetStatResult getStat(AbsPathView i_path) const = 0;
virtual cppcoro::generator<EnumerateEntry> enumerate(const AbsPath& i_path) const = 0;
virtual cppcoro::generator<EnumerateEntry> enumerateRecursively(const AbsPath& i_path) const = 0;
virtual cppcoro::generator<EnumerateEntry> enumerate(AbsPath i_path) const = 0;
virtual cppcoro::generator<EnumerateEntry> enumerateRecursively(AbsPath i_path) const = 0;
virtual ConvertToNativePathResult convertToNativePath(const AbsPath& i_path) const = 0;
virtual ConvertToNativePathResult convertToNativePath(AbsPathView i_path) const = 0;
protected:
IPack() = default;
+8 -8
View File
@@ -13,17 +13,17 @@ public:
using SinkFlag = IFilesystem::SinkFlag;
using SinkFlags = IFilesystem::SinkFlags;
virtual OpenSinkResult openSink(const AbsPath& i_path, Mode i_mode, SinkFlags i_flags = SinkFlags()) = 0;
virtual OpenStreamSinkResult openStreamSink(const AbsPath& i_path, Mode i_mode, SinkFlags i_flags = SinkFlags()) = 0;
virtual OpenMapSinkResult openMapSink(const AbsPath& i_path, Mode i_mode, size_t i_size, SinkFlags i_flags = SinkFlags()) = 0;
virtual OpenSinkResult openSink(AbsPathView i_path, Mode i_mode, SinkFlags i_flags = SinkFlags()) = 0;
virtual OpenStreamSinkResult openStreamSink(AbsPathView i_path, Mode i_mode, SinkFlags i_flags = SinkFlags()) = 0;
virtual OpenMapSinkResult openMapSink(AbsPathView i_path, Mode i_mode, size_t i_size, SinkFlags i_flags = SinkFlags()) = 0;
virtual RemoveResult remove(const AbsPath& i_path) = 0;
virtual RenameResult rename(const AbsPath& i_path, const AbsPath& i_newPath) = 0;
virtual RemoveResult remove(AbsPathView i_path) = 0;
virtual RenameResult rename(AbsPathView i_path, AbsPathView i_newPath) = 0;
virtual MakeFolderResult makeFolder(const AbsPath& i_path) = 0;
virtual RemoveRecursivelyResult removeRecursively(const AbsPath& i_path) = 0;
virtual MakeFolderResult makeFolder(AbsPathView i_path) = 0;
virtual RemoveRecursivelyResult removeRecursively(AbsPathView i_path) = 0;
virtual SetWriteTimeResult setWriteTime(const AbsPath& i_path, time_t i_time) = 0;
virtual SetWriteTimeResult setWriteTime(AbsPathView i_path, time_t i_time) = 0;
};
}
+24 -24
View File
@@ -21,46 +21,46 @@ public:
NativeFilesystem() = default;
explicit NativeFilesystem(CheckFlags checkFlags);
OpenSourceResult openSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const override;
OpenStreamSourceResult openStreamSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const override;
OpenMapSourceResult openMapSource(const AbsPath& path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override;
OpenSinkResult openSink(const AbsPath& path, Mode mode, SinkFlags flags = SinkFlags()) override;
OpenStreamSinkResult openStreamSink(const AbsPath& path, Mode mode, SinkFlags flags = SinkFlags()) override;
OpenMapSinkResult openMapSink(const AbsPath& path, Mode mode, size_t size, SinkFlags flags = SinkFlags()) override;
OpenSourceResult openSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
OpenStreamSourceResult openStreamSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
OpenMapSourceResult openMapSource(AbsPathView path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override;
OpenSinkResult openSink(AbsPathView path, Mode mode, SinkFlags flags = SinkFlags()) override;
OpenStreamSinkResult openStreamSink(AbsPathView path, Mode mode, SinkFlags flags = SinkFlags()) override;
OpenMapSinkResult openMapSink(AbsPathView path, Mode mode, size_t size, SinkFlags flags = SinkFlags()) override;
ConvertToNativePathResult convertToNativePath(const AbsPath& path) const override;
ConvertToNativePathResult convertToNativePath(AbsPathView path) const override;
IsFileResult isFile(const AbsPath& path) const override;
IsFolderResult isFolder(const AbsPath& path) const override;
ExistsResult exists(const AbsPath& path) const override;
IsFileResult isFile(AbsPathView path) const override;
IsFolderResult isFolder(AbsPathView path) const override;
ExistsResult exists(AbsPathView path) const override;
MakeFolderResult makeFolder(const AbsPath& path) override;
MakeFolderResult makeFolder(AbsPathView path) override;
RenameResult rename(const AbsPath& path, const AbsPath& newPath) override;
RenameResult rename(AbsPathView path, AbsPathView newPath) override;
RemoveResult remove(const AbsPath& path) override;
RemoveRecursivelyResult removeRecursively(const AbsPath& path) override;
RemoveResult remove(AbsPathView path) override;
RemoveRecursivelyResult removeRecursively(AbsPathView path) override;
CopyResult copy(const AbsPath& path, const AbsPath& newPath) override;
CopyResult copy(AbsPathView path, AbsPathView newPath) override;
MakeHardLinkResult makeHardLink(const AbsPath& sourcePath, const AbsPath& linkPath) override;
MakeSoftLinkResult makeSymLink(const AbsPath& sourcePath, const AbsPath& linkPath) override;
MakeHardLinkResult makeHardLink(AbsPathView sourcePath, AbsPathView linkPath) override;
MakeSoftLinkResult makeSymLink(AbsPathView sourcePath, AbsPathView linkPath) override;
SetWriteTimeResult setWriteTime(const AbsPath& path, time_t time) override;
SetWriteTimeResult setWriteTime(AbsPathView path, time_t time) override;
GetStatResult getStat(const AbsPath& path) const override;
GetStatResult getStat(AbsPathView path) const override;
cppcoro::generator<EnumerateEntry> enumerate(const AbsPath& path) const override;
cppcoro::generator<EnumerateEntry> enumerateRecursively(const AbsPath& path) const override;
cppcoro::generator<EnumerateEntry> enumerate(AbsPath path) const override;
cppcoro::generator<EnumerateEntry> enumerateRecursively(AbsPath path) const override;
AbsPath getCurrentFolder() const;
tl::result<Error> setCurrentFolder(const AbsPath& path);
tl::result<Error> setCurrentFolder(AbsPathView path);
typedef tl::result<tl::vector<tl::string>, Error> EnumerateFilesResult;
EnumerateFilesResult enumerateFiles(const AbsPath& fullPath) const;
EnumerateFilesResult enumerateFiles(AbsPathView fullPath) const;
typedef tl::result<tl::vector<tl::string>, Error> EnumerateFoldersResult;
EnumerateFoldersResult enumerateFolders(const AbsPath& fullPath) const;
EnumerateFoldersResult enumerateFolders(AbsPathView fullPath) const;
AbsPath makeAbsPath(const tl::string& string) const;
+2 -2
View File
@@ -8,8 +8,8 @@ namespace fs
namespace native_utils
{
bool validateCaseSensitiveFilename(const AbsPath& filePath) noexcept;
bool validateCaseSensitiveFolder(const AbsPath& folderPath) noexcept;
bool validateCaseSensitiveFilename(AbsPathView filePath) noexcept;
bool validateCaseSensitiveFolder(AbsPathView folderPath) noexcept;
typedef eastl::fixed_string<wchar_t, 1024> wstring_t;
typedef eastl::fixed_string<char, 1024> string_t;
+3 -3
View File
@@ -13,8 +13,8 @@ FS_API ReadStreamResult readStream(tl::memory_buffer& buffer, IStreamSource& sou
FS_API ReadStreamResult readStream(std::string& buffer, IStreamSource& source, size_t bufferSize = 0);
FS_API ReadStreamResult readStream(eastl::string& buffer, IStreamSource& source, size_t bufferSize = 0);
FS_API ReadStreamResult readFile(tl::memory_buffer& buffer, IFilesystem& filesystem, const AbsPath& filePath, size_t bufferSize = 0);
FS_API ReadStreamResult readFile(std::string& buffer, IFilesystem& filesystem, const AbsPath& filePath, size_t bufferSize = 0);
FS_API ReadStreamResult readFile(eastl::string& buffer, IFilesystem& filesystem, const AbsPath& filePath, size_t bufferSize = 0);
FS_API ReadStreamResult readFile(tl::memory_buffer& buffer, IFilesystem& filesystem, AbsPathView filePath, size_t bufferSize = 0);
FS_API ReadStreamResult readFile(std::string& buffer, IFilesystem& filesystem, AbsPathView filePath, size_t bufferSize = 0);
FS_API ReadStreamResult readFile(eastl::string& buffer, IFilesystem& filesystem, AbsPathView filePath, size_t bufferSize = 0);
}
@@ -8,11 +8,11 @@
namespace fs
{
class FS_API StreamSourceToSourceAdapter final : public IMapSource
class FS_API StreamSourceToMapSourceAdapter final : public IMapSource
{
public:
explicit StreamSourceToSourceAdapter(tl::unique_ref<IStreamSource>&& i_srcSource);
~StreamSourceToSourceAdapter() override = default;
explicit StreamSourceToMapSourceAdapter(tl::unique_ref<IStreamSource> i_srcSource);
~StreamSourceToMapSourceAdapter() override = default;
tl::optional<Error> getLastError() const override;
+10 -10
View File
@@ -12,21 +12,21 @@ namespace fs
class FS_API WritableFolderPack final : virtual public IWritablePack, public FolderPack
{
public:
explicit WritableFolderPack(AbsPath location);
WritableFolderPack(tl::lent_ref<IFilesystem> filesystem, AbsPath location);
explicit WritableFolderPack(AbsPathView location);
WritableFolderPack(tl::lent_ref<IFilesystem> filesystem, AbsPathView location);
~WritableFolderPack() override = default;
OpenSinkResult openSink(const AbsPath& i_path, Mode i_mode, SinkFlags i_flags = SinkFlags()) override;
OpenStreamSinkResult openStreamSink(const AbsPath& i_path, Mode i_mode, SinkFlags i_flags = SinkFlags()) override;
OpenMapSinkResult openMapSink(const AbsPath& i_path, Mode i_mode, size_t i_size, SinkFlags i_flags = SinkFlags()) override;
OpenSinkResult openSink(AbsPathView i_path, Mode i_mode, SinkFlags i_flags = SinkFlags()) override;
OpenStreamSinkResult openStreamSink(AbsPathView i_path, Mode i_mode, SinkFlags i_flags = SinkFlags()) override;
OpenMapSinkResult openMapSink(AbsPathView i_path, Mode i_mode, size_t i_size, SinkFlags i_flags = SinkFlags()) override;
RemoveResult remove(const AbsPath& i_path) override;
RenameResult rename(const AbsPath& i_path, const AbsPath& i_newPath) override;
RemoveResult remove(AbsPathView i_path) override;
RenameResult rename(AbsPathView i_path, AbsPathView i_newPath) override;
MakeFolderResult makeFolder(const AbsPath& i_path) override;
RemoveRecursivelyResult removeRecursively(const AbsPath& i_path) override;
MakeFolderResult makeFolder(AbsPathView i_path) override;
RemoveRecursivelyResult removeRecursively(AbsPathView i_path) override;
SetWriteTimeResult setWriteTime(const AbsPath& i_path, time_t i_time) override;
SetWriteTimeResult setWriteTime(AbsPathView i_path, time_t i_time) override;
};
}
-37
View File
@@ -1,37 +0,0 @@
#pragma once
#include "fs/AbsPath.h"
#include "fs/zip/ZipWriter.h"
#include "tl/ptr.h"
namespace fs
{
class IFilesystem;
//////////////////////////////////////////////////////////////////////////
class FS_API DeflateFileWriter
{
public:
//compression level: 0 to 9
DeflateFileWriter(AbsPath i_filePath, tl::lent_ref<IFilesystem> i_filesystem, uint8_t i_compressionLevel);
DeflateFileWriter(const DeflateFileWriter&) = delete;
DeflateFileWriter& operator=(const DeflateFileWriter&) = delete;
DeflateFileWriter(DeflateFileWriter&&) = default;
DeflateFileWriter& operator=(DeflateFileWriter&&) = default;
ZipWriter::DataWriterResult operator()(IStreamSink& i_sink);
private:
AbsPath m_filePath;
tl::lent_ref<IFilesystem> m_filesystem;
uint8_t m_compressionLevel = 9;
};
//////////////////////////////////////////////////////////////////////////
}
-37
View File
@@ -1,37 +0,0 @@
#pragma once
#include "fs/IStreamSource.h"
#include "fs/zip/ZipWriter.h"
namespace fs
{
//////////////////////////////////////////////////////////////////////////
class ISource;
//////////////////////////////////////////////////////////////////////////
class FS_API DeflateSinkWriter
{
public:
//compression level: 0 to 9
DeflateSinkWriter(IStreamSource& source, uint8_t compressionLevel);
DeflateSinkWriter(tl::span<const uint8_t> data, uint8_t compressionLevel);
DeflateSinkWriter(const DeflateSinkWriter&) = delete;
DeflateSinkWriter& operator=(const DeflateSinkWriter&) = delete;
DeflateSinkWriter(DeflateSinkWriter&&) = default;
DeflateSinkWriter& operator=(DeflateSinkWriter&&) = default;
ZipWriter::DataWriterResult operator()(IStreamSink& sink);
private:
IStreamSource* m_source = nullptr;
tl::span<const uint8_t> m_data;
uint8_t m_compressionLevel = 9;
};
//////////////////////////////////////////////////////////////////////////
}
-35
View File
@@ -1,35 +0,0 @@
#pragma once
#include "fs/AbsPath.h"
#include "fs/zip/ZipWriter.h"
#include "tl/ptr.h"
namespace fs
{
class IFilesystem;
//////////////////////////////////////////////////////////////////////////
class FS_API StoreFileWriter
{
public:
StoreFileWriter(AbsPath i_filePath, tl::lent_ref<IFilesystem> i_filesystem);
StoreFileWriter(const StoreFileWriter&) = delete;
StoreFileWriter& operator=(const StoreFileWriter&) = delete;
StoreFileWriter(StoreFileWriter&&) = default;
StoreFileWriter& operator=(StoreFileWriter&&) = default;
ZipWriter::DataWriterResult operator()(IStreamSink& i_sink);
private:
AbsPath m_filePath;
tl::lent_ref<IFilesystem> m_filesystem;
};
//////////////////////////////////////////////////////////////////////////
}
-32
View File
@@ -1,32 +0,0 @@
#pragma once
#include "fs/zip/ZipWriter.h"
namespace fs
{
//////////////////////////////////////////////////////////////////////////
class ISource;
//////////////////////////////////////////////////////////////////////////
class FS_API StoreSinkWriter
{
public:
explicit StoreSinkWriter(ISource& source);
StoreSinkWriter(const StoreSinkWriter&) = delete;
StoreSinkWriter& operator=(const StoreSinkWriter&) = delete;
StoreSinkWriter(StoreSinkWriter&&) = default;
StoreSinkWriter& operator=(StoreSinkWriter&&) = default;
ZipWriter::DataWriterResult operator()(IStreamSink& sink);
private:
tl::reference_wrapper<ISource> m_inSource;
};
//////////////////////////////////////////////////////////////////////////
}
-158
View File
@@ -1,158 +0,0 @@
#pragma once
#include "tl/flag_set.h"
#include "fs/Api.h"
namespace fs
{
class FS_API ZipBase
{
public:
enum class GeneralBitFlag : uint16_t
{
Encrypted = 1 << 0,
CompressionMethodSpecific1 = 1 << 1,
CompressionMethodSpecific2 = 1 << 2,
DataDescriptorNeeded = 1 << 3,
StrongEncryption = 1 << 6,
LanguageEncodingFlag = 1 << 11,
LocalHeaderFieldsMasked = 1 << 13,
};
typedef tl::flag_set<GeneralBitFlag> GeneralBitFlags;
enum class CompressionMethod : uint16_t
{
Store = 0,
Shrunk = 1,
Reduced1 = 2,
Reduced2 = 3,
Reduced3 = 4,
Reduced4 = 5,
Implode = 6,
//Reserved = 7,
Deflate = 8,
Deflate64 = 9,
PKWareImplode = 10,
//Reserved = 11,
BZip2 = 12,
//Reserved = 13,
LZMA = 14,
//Reserved = 15,
//Reserved = 16,
//Reserved = 17,
Terse = 18,
LZ77 = 19,
LZ4 = 20, // non-standard
ZStd = 21, // non-standard
WavPack = 97,
PPMd = 98,
};
protected:
//////////////////////////////////////////////////////////////////////////
//These structs follow pretty closely the https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT standard
#pragma pack(push, 1)
struct LocalFileHeader
{
static constexpr uint32_t k_signature = 0x04034b50u;
uint32_t signature = k_signature;
uint16_t versionNeededToExtract = 0;
uint16_t generalBitFlag = 0;
uint16_t compressionMethod = 0;
uint16_t lastModFileTime = 0;
uint16_t lastModFileDate = 0;
uint32_t crc32 = 0;
uint32_t compressedSize = 0;
uint32_t uncompressedSize = 0;
uint16_t filenameLength = 0;
uint16_t extraFieldLength = 0;
};
struct DataDescriptor
{
uint32_t crc32 = 0;
uint32_t compressedSize = 0;
uint32_t uncompressedSize = 0;
};
struct CentralDirectoryFileHeader
{
static constexpr uint32_t k_signature = 0x02014b50u;
uint32_t signature = k_signature;
uint16_t versionMadeBy = 0;
uint16_t versionNeededToExtract = 0;
uint16_t generalBitFlag = 0;
uint16_t compressionMethod = 0;
uint16_t lastModFileTime = 0;
uint16_t lastModFileDate = 0;
uint32_t crc32 = 0;
uint32_t compressedSize = 0;
uint32_t uncompressedSize = 0;
uint16_t filenameLength = 0;
uint16_t extraFieldLength = 0;
uint16_t fileCommentLength = 0;
uint16_t diskNumberStart = 0;
uint16_t internalFileAttributes = 0;
uint32_t externalFileAttributes = 0;
uint32_t localHeaderOffset = 0;
};
struct EndOfCentralDirectoryRecord
{
static constexpr uint32_t k_signature = 0x06054b50u;
uint32_t signature = k_signature;
uint16_t diskNumber = 0;
uint16_t centralDirectoryStartDiskNumber = 0;
uint16_t centralDirectoryRecordCountOnThisDisk = 0;
uint16_t centralDirectoryRecordCount = 0;
uint32_t centralDirectorySize = 0;
uint32_t centralDirectoryOffset = 0;
uint16_t zipFileCommentLength = 0;
};
struct ExtendedInformationExtraField64
{
static constexpr uint32_t k_tag = 0x0001;
uint16_t tag = k_tag;
uint16_t size = 0;
uint64_t originalSize = 0;
uint64_t compressedSize = 0;
uint64_t localHeaderOffset = 0;
uint32_t diskNumber = 0;
};
struct EndOfCentralDirectoryRecord64
{
static constexpr uint32_t k_signature = 0x06064b50u;
uint32_t signature = k_signature;
uint64_t endOfCentralDirectorySize = 0;
uint16_t versionMadeBy = 0;
uint16_t versionNeededToExtract = 0;
uint32_t diskNumber = 0;
uint32_t centralDirectoryStartDiskNumber = 0;
uint64_t centralDirectoryRecordCountOnThisDisk = 0;
uint64_t centralDirectoryRecordCount = 0;
uint64_t centralDirectorySize = 0;
uint64_t centralDirectoryOffset = 0;
};
struct EndOfCentralDirectoryLocator64
{
static constexpr uint32_t k_signature = 0x07064b50u;
uint32_t signature = k_signature;
uint32_t centralDirectoryStartDiskNumber = 0;
uint64_t endOfCentralDirectoryRecordOffset = 0;
uint32_t diskCount = 0;
};
#pragma pack(pop)
static void computeMsDosTime(time_t time, uint16_t& o_date, uint16_t& o_time);
static CentralDirectoryFileHeader computeCentralDirectoryFileHeader(const LocalFileHeader& header, bool zip64);
};
}
+61 -38
View File
@@ -3,18 +3,40 @@
#include "tl/result.h"
#include "tl/string.h"
#include "tl/vector_map.h"
#include "fs/IStreamSource.h"
#include "fs/IPack.h"
#include "fs/AbsPath.h"
#include "fs/zip/ZipReader.h"
#include "fs/Api.h"
struct zip;
struct zip_source;
struct zip_file;
namespace tl
{
template<> struct ptr_traits<zip>
{
static constexpr inline bool custom_deleter = true;
static constexpr inline bool requires_virtual_destructor_check = false;
};
//template<> struct ptr_traits<zip_source>
//{
// static constexpr inline bool custom_deleter = true;
// static constexpr inline bool requires_virtual_destructor_check = false;
//};
template<> struct ptr_traits<zip_file>
{
static constexpr inline bool custom_deleter = true;
static constexpr inline bool requires_virtual_destructor_check = false;
};
}
namespace fs
{
class MapSourceView;
class FS_API ZipPack final : virtual public IPack
class FS_API ZipPack final : public IPack
{
public:
ZipPack() = default;
@@ -22,66 +44,71 @@ public:
typedef tl::result<tl::unique_ref<ZipPack>, Error> CreateResult;
static CreateResult create(tl::unique_ref<IMapSource> zipFileSource);
static CreateResult create(tl::lent_ref<const IFilesystem> filesystem, AbsPath zipFileLocation);
static CreateResult create(tl::unique_ref<IMapSource> source);
static CreateResult create(tl::lent_ref<const IFilesystem> filesystem, AbsPathView path);
virtual void setEncryptionData(const tl::string& key, uint32_t rounds);
void setEncryptionData(const tl::string& key, uint32_t rounds);
OpenSourceResult openSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const override;
OpenStreamSourceResult openStreamSource(const AbsPath& path, SourceFlags flags = SourceFlags()) const override;
OpenMapSourceResult openMapSource(const AbsPath& path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override;
OpenSourceResult openSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
OpenStreamSourceResult openStreamSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override;
OpenMapSourceResult openMapSource(AbsPathView path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override;
IsFileResult isFile(const AbsPath& path) const override;
IsFolderResult isFolder(const AbsPath& path) const override;
ExistsResult exists(const AbsPath& path) const override;
IsFileResult isFile(AbsPathView path) const override;
IsFolderResult isFolder(AbsPathView path) const override;
ExistsResult exists(AbsPathView path) const override;
GetStatResult getStat(const AbsPath& path) const override;
GetStatResult getStat(AbsPathView path) const override;
cppcoro::generator<EnumerateEntry> enumerate(const AbsPath& path) const override;
cppcoro::generator<EnumerateEntry> enumerateRecursively(const AbsPath& path) const override;
cppcoro::generator<EnumerateEntry> enumerate(AbsPath path) const override;
cppcoro::generator<EnumerateEntry> enumerateRecursively(AbsPath path) const override;
tl::result<AbsPath, Error> convertToNativePath(const AbsPath& path) const override;
tl::result<AbsPath, Error> convertToNativePath(AbsPathView path) const override;
struct ZipData
{
tl::unique_ptr<IMapSource> fsMapSource;
tl::lent_ptr<const IFilesystem> filesystem;
AbsPath path;
tl::unique_ptr<ISource> fsSource;
uint64_t cachedSize = uint64_t(-1);
//tl::unique_ptr<zip_source> zipSource;
tl::unique_ptr<zip> zipArchive;
};
protected:
struct File;
struct Folder;
struct EntryIndex;
ZipPack(tl::unique_ref<IMapSource> zipFileSource, ZipReader zipReader);
ZipPack(tl::lent_ref<const IFilesystem> filesystem, AbsPath zipFileLocation, ZipReader zipReader);
ZipPack(tl::shared_ptr<ZipData> data);
OpenMapSourceResult openRawMapSource(const File& file, MapView mapView) const;
OpenSourceResult openRawSource(const File& file) const;
//OpenMapSourceResult openRawMapSource(const File& file, MapView mapView) const;
//OpenSourceResult openRawSource(const File& file) const;
OpenSourceResult openZipSource(const File& file) const;
OpenMapSourceResult openZipMapSource(const File& file) const;
OpenStreamSourceResult openZipStreamSource(const File& file) const;
OpenSourceResult _openSource(const File& file) const;
OpenMapSourceResult _openMapSource(const File& file) const;
OpenStreamSourceResult _openStreamSource(const File& file) const;
uint16_t getOrAddFolder(AbsPath folderPath, tl::vector<tl::vector<EntryIndex>>& io_childrenIndices);
void createEntries(ZipReader zipReader);
uint16_t getOrAddFolder(AbsPathView folderPath, tl::vector<tl::vector<EntryIndex>>& io_childrenIndices);
void createEntries(zip& archive);
struct File
{
uint16_t zipIndex = 0; //index inside the zip archive
tl::string name;
uint8_t isCompressed : 1;
uint8_t uncompressedSizeH = 0;
uint8_t compressedSizeH = 0;
uint8_t dataOffsetH = 0;
uint16_t parentIndex = 0;
uint32_t lastModTimePoint = 0;
uint32_t uncompressedSizeL = 0;
uint32_t compressedSizeL = 0;
uint32_t dataOffsetL = 0;
};
static_assert(sizeof(File) <= sizeof(tl::string) + 40, "Check your sizes!!!");
struct Folder
{
uint16_t zipIndex = 0; //index inside the zip archive
tl::string name;
uint16_t parentIndex = 0;
uint16_t childrenStartIndex = 0; // this is an index inside m_childrenIndices
uint16_t childrenCount = 0;
uint32_t lastModTimePoint = 0;
};
static_assert(sizeof(Folder) <= sizeof(tl::string) + 20, "Check your sizes!!!");
@@ -99,12 +126,8 @@ protected:
static_assert(sizeof(EntryIndex) == 4, "Check your sizes!!!");
private:
tl::lent_ptr<const IFilesystem> m_filesystem;
mutable std::mutex m_zipMapSourceLock;
tl::unique_ptr<IMapSource> m_zipMapSource;
AbsPath m_zipFileLocation;
tl::shared_ptr<ZipData> m_zipData;
tl::string m_encryptionKey;
uint32_t m_encryptionRounds = 32;
-63
View File
@@ -1,63 +0,0 @@
#pragma once
#include "ZipBase.h"
#include "tl/memory_buffer.h"
#include "tl/result.h"
#include "tl/vector.h"
namespace fs
{
//////////////////////////////////////////////////////////////////////////
class ISource;
//////////////////////////////////////////////////////////////////////////
class ZipReader : public ZipBase
{
public:
enum class ErrorCode : uint8_t
{
InvalidStream,
BadSignature,
BadOffset,
CorruptedFile,
};
typedef tl::error<ErrorCode> Error;
typedef tl::result<ZipReader, Error> CreateResult;
static CreateResult create(ISource& source);
struct Entry
{
tl::string name;
CompressionMethod compressionMethod = CompressionMethod::Store;
GeneralBitFlags generalBitFlags;
uint64_t uncompressedSize = 0;
uint64_t compressedSize = 0;
uint32_t crc32 = 0;
uint64_t localHeaderOffset = 0;
uint64_t dataOffset = 0;
time_t lastModTimePoint = 0;
tl::memory_buffer comment;
};
size_t getEntryCount() const;
const Entry& getEntry(size_t index) const;
typedef tl::result<void, Error> SeekResult;
SeekResult seekSourceToEntryData(const Entry& entry, ISource& o_source) const;
private:
explicit ZipReader(tl::vector<Entry> entries);
typedef tl::result<tl::pair<uint64_t, uint64_t>, Error> CentralDirectoryResult;
static CentralDirectoryResult findCentralDirectoryBounds(ISource& source);
tl::vector<Entry> m_entries;
};
//////////////////////////////////////////////////////////////////////////
}
+4 -4
View File
@@ -9,11 +9,11 @@ namespace fs
class ISink;
typedef tl::result<void, Error> UnzipResult;
FS_API UnzipResult unzipSource(IFilesystem& dstFilesystem, const AbsPath& filePath, tl::unique_ref<IMapSource> source);
FS_API UnzipResult unzipFile(IFilesystem& dstFilesystem, const AbsPath& filePath, tl::lent_ref<const IFilesystem> filesystem, AbsPath srcFilePath);
FS_API UnzipResult unzipSource(IFilesystem& dstFilesystem, AbsPathView filePath, tl::unique_ref<IMapSource> source);
FS_API UnzipResult unzipFile(IFilesystem& dstFilesystem, AbsPathView filePath, tl::lent_ref<const IFilesystem> filesystem, AbsPathView srcFilePath);
typedef tl::result<void, Error> ZipResult;
FS_API ZipResult zipToSink(ISink& sink, tl::lent_ref<IFilesystem> filesystem, const AbsPath& path, uint8_t compressionLevel, size_t fileDataAlignment = 0);
FS_API ZipResult zipToFile(IFilesystem& dstFilesystem, const AbsPath& dstFilePath, tl::lent_ref<IFilesystem> filesystem, const AbsPath& path, uint8_t compressionLevel, size_t fileDataAlignment = 0);
FS_API ZipResult zipToSink(ISink& sink, tl::lent_ref<IFilesystem> filesystem, AbsPathView path, uint8_t compressionLevel);
FS_API ZipResult zipToFile(IFilesystem& dstFilesystem, AbsPathView dstFilePath, tl::lent_ref<IFilesystem> filesystem, AbsPathView path, uint8_t compressionLevel);
}
+28 -40
View File
@@ -1,77 +1,65 @@
#pragma once
#include "ZipBase.h"
#include "fs/Api.h"
#include <tl/memory_buffer.h>
#include <tl/span.h>
#include <tl/vector.h>
#include <tl/result.h>
#include <tl/optional.h>
#include "fs/zip/ZipPack.h"
namespace fs
{
//////////////////////////////////////////////////////////////////////////
class IStreamSource;
class ISource;
class IStreamSink;
class ISink;
//////////////////////////////////////////////////////////////////////////
class FS_API ZipWriter : public ZipBase
class FS_API ZipWriter
{
public:
struct DataWriterPayload
{
CompressionMethod compressionMethod;
uint32_t uncompressedCRC32 = 0; //mandatory!!!
uint64_t uncompressedSize = 0; //optional, will be set to the written size if == 0
};
//0 - no compression (Store)
//9 - max compression (Deflate)
using Compression = uint8_t;
using DataWriterError = tl::generic_error;
using DataWriterResult = tl::result<DataWriterPayload, DataWriterError>;
ZipWriter(ISink& sink);
~ZipWriter();
using DataWriter = tl::function<DataWriterResult(IStreamSink& sink)>;
ZipWriter(ISink& sink, size_t fileDataAlignment);
~ZipWriter() = default;
tl::result<void> addFile(tl::string name, const DataWriter& dataWriter);
tl::result<void> addFile(tl::string name, tl::optional<time_t> lastModificationTime, const DataWriter& dataWriter);
tl::result<void> addBuffer(tl::string name, Compression compression, tl::span<const uint8_t> buffer);
tl::result<void> addBuffer(tl::string name, time_t lastModificationTime, Compression compression, tl::span<const uint8_t> buffer);
tl::result<void> addBuffer(tl::string name,
tl::span<const uint8_t> comment,
tl::span<const uint8_t> extraField,
time_t lastModificationTime,
Compression compression,
tl::span<const uint8_t> buffer);
tl::result<void> addFile(tl::string name, Compression compression, ISource& source);
tl::result<void> addFile(tl::string name, time_t lastModificationTime, Compression compression, ISource& source);
tl::result<void> addFile(tl::string name,
tl::span<const uint8_t> comment,
tl::span<const uint8_t> extraField,
GeneralBitFlags generalBitFlags,
tl::optional<time_t> lastModificationTime,
const DataWriter& dataWriter);
time_t lastModificationTime,
Compression compression,
ISource& source);
void finish();
private:
uint64_t computePadding(uint64_t offset, const LocalFileHeader& header) const;
tl::result<uint64_t> _addSource(tl::string name,
tl::span<const uint8_t> comment,
tl::span<const uint8_t> extraField,
time_t lastModificationTime,
Compression compression,
zip_source* source);
ISink& m_sink;
size_t m_fileDataAlignment = 0;
struct CentralDirectoryRecord
{
uint64_t compressedSize = 0;
uint64_t uncompressedSize = 0;
uint64_t localHeaderOffset = 0;
CentralDirectoryFileHeader header;
tl::string name;
tl::memory_buffer comment;
tl::memory_buffer extraField;
bool zip64 = false;
tl::unique_ptr<zip> m_zipArchive;
};
tl::vector<CentralDirectoryRecord> m_records;
tl::memory_buffer m_buffer;
};
//////////////////////////////////////////////////////////////////////////
}
+2 -2
View File
@@ -210,7 +210,7 @@ CRC32StreamResult crc32Stream(IStreamSource& source, uint32_t crc, size_t buffer
//////////////////////////////////////////////////////////////////////////
CRC32StreamResult crc32File(const IFilesystem& filesystem, const AbsPath& filePath, uint32_t crc, size_t bufferSize)
CRC32StreamResult crc32File(const IFilesystem& filesystem, AbsPathView filePath, uint32_t crc, size_t bufferSize)
{
OUTCOME_TRY(const auto source, filesystem.openStreamSource(filePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return crc32Stream(*source, crc, bufferSize);
@@ -245,7 +245,7 @@ CRC64StreamResult crc64Stream(IStreamSource& source, uint64_t crc, size_t buffer
//////////////////////////////////////////////////////////////////////////
CRC64StreamResult crc64File(const IFilesystem& filesystem, const AbsPath& filePath, uint64_t crc, size_t bufferSize)
CRC64StreamResult crc64File(const IFilesystem& filesystem, AbsPathView filePath, uint64_t crc, size_t bufferSize)
{
OUTCOME_TRY(const auto source, filesystem.openStreamSource(filePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return crc64Stream(*source, crc, bufferSize);
+3 -3
View File
@@ -60,7 +60,7 @@ CopyStreamResult copyStream(IStreamSink& sink, IStreamSource& source, const Proc
//////////////////////////////////////////////////////////////////////////
CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, const AbsPath& filePath, size_t bufferSize)
CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, AbsPathView filePath, size_t bufferSize)
{
OUTCOME_TRY(const auto source, filesystem.openStreamSource(filePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return copyStream(sink, *source, bufferSize);
@@ -68,13 +68,13 @@ CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, cons
//////////////////////////////////////////////////////////////////////////
CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, const AbsPath& filePath, const ProcessDataCallback& dataCallback, size_t bufferSize)
CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, AbsPathView filePath, const ProcessDataCallback& dataCallback, size_t bufferSize)
{
OUTCOME_TRY(const auto source, filesystem.openStreamSource(filePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return copyStream(sink, *source, dataCallback, bufferSize);
}
CopyStreamResult copyFile(IFilesystem& dstFilesystem, const AbsPath& dstFilePath, const IFilesystem& srcFilesystem, const AbsPath& srcFilePath, size_t bufferSize)
CopyStreamResult copyFile(IFilesystem& dstFilesystem, AbsPathView dstFilePath, const IFilesystem& srcFilesystem, AbsPathView srcFilePath, size_t bufferSize)
{
OUTCOME_TRY(const auto sink, dstFilesystem.openStreamSink(dstFilePath, fs::Mode::CreateOrOpenAndClear));
OUTCOME_TRY(const auto source, srcFilesystem.openStreamSource(srcFilePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
+34 -30
View File
@@ -25,14 +25,14 @@ tl::atomic<int> s_lastId(0);
//////////////////////////////////////////////////////////////////////////
tl::result<CustomFilesystem::PackId> CustomFilesystem::mountFront(AbsPath mountPoint, tl::unique_ref<IPack> pack)
tl::result<CustomFilesystem::PackId> CustomFilesystem::mountFront(AbsPathView mountPoint, tl::unique_ref<IPack> pack)
{
return mount(std::move(mountPoint), std::move(pack), MountPolicy::Front);
}
//////////////////////////////////////////////////////////////////////////
tl::result<CustomFilesystem::PackId> CustomFilesystem::mountBack(AbsPath mountPoint, tl::unique_ref<IPack> pack)
tl::result<CustomFilesystem::PackId> CustomFilesystem::mountBack(AbsPathView mountPoint, tl::unique_ref<IPack> pack)
{
return mount(std::move(mountPoint), std::move(pack), MountPolicy::Back);
}
@@ -67,7 +67,7 @@ tl::unique_ptr<IPack> CustomFilesystem::unmount(PackId packId)
//////////////////////////////////////////////////////////////////////////
OpenSourceResult CustomFilesystem::openSource(const AbsPath& path, SourceFlags flags) const
OpenSourceResult CustomFilesystem::openSource(AbsPathView path, SourceFlags flags) const
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -93,7 +93,7 @@ OpenSourceResult CustomFilesystem::openSource(const AbsPath& path, SourceFlags f
//////////////////////////////////////////////////////////////////////////
OpenStreamSourceResult CustomFilesystem::openStreamSource(const AbsPath& path, SourceFlags flags) const
OpenStreamSourceResult CustomFilesystem::openStreamSource(AbsPathView path, SourceFlags flags) const
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -119,7 +119,7 @@ OpenStreamSourceResult CustomFilesystem::openStreamSource(const AbsPath& path, S
//////////////////////////////////////////////////////////////////////////
OpenMapSourceResult CustomFilesystem::openMapSource(const AbsPath& path, MapView mapView, SourceFlags flags) const
OpenMapSourceResult CustomFilesystem::openMapSource(AbsPathView path, MapView mapView, SourceFlags flags) const
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -145,7 +145,7 @@ OpenMapSourceResult CustomFilesystem::openMapSource(const AbsPath& path, MapView
//////////////////////////////////////////////////////////////////////////
OpenMapSinkResult CustomFilesystem::openMapSink(const AbsPath& path, Mode mode, size_t size, SinkFlags flags)
OpenMapSinkResult CustomFilesystem::openMapSink(AbsPathView path, Mode mode, size_t size, SinkFlags flags)
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -172,7 +172,7 @@ OpenMapSinkResult CustomFilesystem::openMapSink(const AbsPath& path, Mode mode,
//////////////////////////////////////////////////////////////////////////
OpenSinkResult CustomFilesystem::openSink(const AbsPath& path, Mode mode, SinkFlags flags)
OpenSinkResult CustomFilesystem::openSink(AbsPathView path, Mode mode, SinkFlags flags)
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -197,7 +197,7 @@ OpenSinkResult CustomFilesystem::openSink(const AbsPath& path, Mode mode, SinkFl
//////////////////////////////////////////////////////////////////////////
OpenStreamSinkResult CustomFilesystem::openStreamSink(const AbsPath& path, Mode mode, SinkFlags flags)
OpenStreamSinkResult CustomFilesystem::openStreamSink(AbsPathView path, Mode mode, SinkFlags flags)
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -222,7 +222,7 @@ OpenStreamSinkResult CustomFilesystem::openStreamSink(const AbsPath& path, Mode
//////////////////////////////////////////////////////////////////////////
ExistsResult CustomFilesystem::exists(const AbsPath& path) const
ExistsResult CustomFilesystem::exists(AbsPathView path) const
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -252,7 +252,7 @@ ExistsResult CustomFilesystem::exists(const AbsPath& path) const
//////////////////////////////////////////////////////////////////////////
IsFileResult CustomFilesystem::isFile(const AbsPath& path) const
IsFileResult CustomFilesystem::isFile(AbsPathView path) const
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -277,7 +277,7 @@ IsFileResult CustomFilesystem::isFile(const AbsPath& path) const
//////////////////////////////////////////////////////////////////////////
RenameResult CustomFilesystem::rename(const AbsPath& path, const AbsPath& newPath)
RenameResult CustomFilesystem::rename(AbsPathView path, AbsPathView newPath)
{
AbsPath fromPackPath;
AbsPath toPackPath;
@@ -304,7 +304,7 @@ RenameResult CustomFilesystem::rename(const AbsPath& path, const AbsPath& newPat
//////////////////////////////////////////////////////////////////////////
CopyResult CustomFilesystem::copy(const AbsPath& path, const AbsPath& newPath)
CopyResult CustomFilesystem::copy(AbsPathView path, AbsPathView newPath)
{
OUTCOME_TRY(const auto source, openStreamSource(path, SourceFlags(SourceFlag::SequentialHint, SourceFlag::Uncached)));
OUTCOME_TRY(const auto destination, openStreamSink(newPath, Mode::CreateOrOpenAndClear));
@@ -318,7 +318,7 @@ CopyResult CustomFilesystem::copy(const AbsPath& path, const AbsPath& newPath)
//////////////////////////////////////////////////////////////////////////
MakeHardLinkResult CustomFilesystem::makeHardLink(const AbsPath& sourcePath, const AbsPath& linkPath)
MakeHardLinkResult CustomFilesystem::makeHardLink(AbsPathView sourcePath, AbsPathView linkPath)
{
OUTCOME_TRY(const auto sp, convertToNativePath(sourcePath));
OUTCOME_TRY(const auto lp, convertToNativePath(linkPath));
@@ -327,7 +327,7 @@ MakeHardLinkResult CustomFilesystem::makeHardLink(const AbsPath& sourcePath, con
//////////////////////////////////////////////////////////////////////////
MakeSoftLinkResult CustomFilesystem::makeSymLink(const AbsPath& sourcePath, const AbsPath& linkPath)
MakeSoftLinkResult CustomFilesystem::makeSymLink(AbsPathView sourcePath, AbsPathView linkPath)
{
OUTCOME_TRY(const auto sp, convertToNativePath(sourcePath));
OUTCOME_TRY(const auto lp, convertToNativePath(linkPath));
@@ -336,7 +336,7 @@ MakeSoftLinkResult CustomFilesystem::makeSymLink(const AbsPath& sourcePath, cons
//////////////////////////////////////////////////////////////////////////
IsFolderResult CustomFilesystem::isFolder(const AbsPath& path) const
IsFolderResult CustomFilesystem::isFolder(AbsPathView path) const
{
AbsPath folderPackPath;
for (const auto& pd : m_packsData)
@@ -360,7 +360,7 @@ IsFolderResult CustomFilesystem::isFolder(const AbsPath& path) const
//////////////////////////////////////////////////////////////////////////
MakeFolderResult CustomFilesystem::makeFolder(const AbsPath& path)
MakeFolderResult CustomFilesystem::makeFolder(AbsPathView path)
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -387,7 +387,7 @@ MakeFolderResult CustomFilesystem::makeFolder(const AbsPath& path)
//////////////////////////////////////////////////////////////////////////
RemoveResult CustomFilesystem::remove(const AbsPath& path)
RemoveResult CustomFilesystem::remove(AbsPathView path)
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -412,7 +412,7 @@ RemoveResult CustomFilesystem::remove(const AbsPath& path)
//////////////////////////////////////////////////////////////////////////
RemoveRecursivelyResult CustomFilesystem::removeRecursively(const AbsPath& path)
RemoveRecursivelyResult CustomFilesystem::removeRecursively(AbsPathView path)
{
for (const EnumerateEntry& ee : enumerate(path))
{
@@ -432,7 +432,7 @@ RemoveRecursivelyResult CustomFilesystem::removeRecursively(const AbsPath& path)
//////////////////////////////////////////////////////////////////////////
ConvertToNativePathResult CustomFilesystem::convertToNativePath(const AbsPath& path) const
ConvertToNativePathResult CustomFilesystem::convertToNativePath(AbsPathView path) const
{
AbsPath folderPackPath;
for (const auto& pd : m_packsData)
@@ -453,7 +453,7 @@ ConvertToNativePathResult CustomFilesystem::convertToNativePath(const AbsPath& p
//////////////////////////////////////////////////////////////////////////
SetWriteTimeResult CustomFilesystem::setWriteTime(const AbsPath& path, time_t time)
SetWriteTimeResult CustomFilesystem::setWriteTime(AbsPathView path, time_t time)
{
AbsPath filePackPath;
for (const auto& pd : m_packsData)
@@ -478,7 +478,7 @@ SetWriteTimeResult CustomFilesystem::setWriteTime(const AbsPath& path, time_t ti
//////////////////////////////////////////////////////////////////////////
GetStatResult CustomFilesystem::getStat(const AbsPath& path) const
GetStatResult CustomFilesystem::getStat(AbsPathView path) const
{
AbsPath folderPackPath;
for (const auto& pd : m_packsData)
@@ -499,7 +499,7 @@ GetStatResult CustomFilesystem::getStat(const AbsPath& path) const
//////////////////////////////////////////////////////////////////////////
cppcoro::generator<EnumerateEntry> CustomFilesystem::enumerate(const AbsPath& path) const
cppcoro::generator<EnumerateEntry> CustomFilesystem::enumerate(AbsPath path) const
{
AbsPath basePackPath;
for (const auto& pd : m_packsData)
@@ -521,7 +521,7 @@ cppcoro::generator<EnumerateEntry> CustomFilesystem::enumerate(const AbsPath& pa
//////////////////////////////////////////////////////////////////////////
cppcoro::generator<EnumerateEntry> CustomFilesystem::enumerateRecursively(const AbsPath& path) const
cppcoro::generator<EnumerateEntry> CustomFilesystem::enumerateRecursively(AbsPath path) const
{
tl::unordered_set<RelPath> checkedFiles;
@@ -547,11 +547,15 @@ cppcoro::generator<EnumerateEntry> CustomFilesystem::enumerateRecursively(const
}
else if (path.is_prefix_of(pd.mountPoint))
{
const RelPath parentPath = path.path_to(pd.mountPoint);
const RelPathView parentPath = path.path_to(pd.mountPoint);
RelPath p = parentPath;
for (EnumerateEntry ee : pd.pack->enumerateRecursively(AbsPath(PosixRootTag::value())))
{
ee.path = parentPath + ee.path;
const size_t eePathSize = ee.path.size();
p += ee.path;
ee.path = p;
p.shrink(eePathSize);
if (checkedFiles.insert(ee.path).second)
co_yield std::move(ee);
}
@@ -561,19 +565,19 @@ cppcoro::generator<EnumerateEntry> CustomFilesystem::enumerateRecursively(const
//////////////////////////////////////////////////////////////////////////
void CustomFilesystem::convertToPackPath(AbsPath& packPath, const AbsPath& path, const AbsPath& mountPoint) const
void CustomFilesystem::convertToPackPath(AbsPath& packPath, AbsPathView path, AbsPathView mountPoint) const
{
RelPath basePath = mountPoint.path_to(path);
RelPathView basePath = mountPoint.prefix_path_to(path);
packPath = PosixRootTag::value();
packPath.reserve(basePath.size() + 1);
for (tl::string& element : basePath)
packPath.push_back(std::move(element));
for (const tl::string& element : basePath)
packPath.push_back(element);
}
//////////////////////////////////////////////////////////////////////////
tl::result<CustomFilesystem::PackId> CustomFilesystem::mount(AbsPath mountPoint, tl::unique_ref<IPack> pack, MountPolicy policy)
tl::result<CustomFilesystem::PackId> CustomFilesystem::mount(AbsPathView mountPoint, tl::unique_ref<IPack> pack, MountPolicy policy)
{
if (!mountPoint.is_valid())
+1 -1
View File
@@ -14,7 +14,7 @@ struct FileMapSink::Impl
mio::ummap_sink sink;
};
FileMapSink::FileMapSink(const AbsPath& filepath,
FileMapSink::FileMapSink(AbsPathView filepath,
size_t size,
Mode mode /*= Mode::CreateOrOpenAndClear*/,
Flags flags /*= Flags()*/)
+2 -2
View File
@@ -18,7 +18,7 @@ struct FileMapSource::Impl
mio::ummap_source source;
};
FileMapSource::FileMapSource(const AbsPath& filepath)
FileMapSource::FileMapSource(AbsPathView filepath)
{
std::error_code error;
mio::ummap_source mmap;
@@ -34,7 +34,7 @@ FileMapSource::FileMapSource(const AbsPath& filepath)
//////////////////////////////////////////////////////////////////////////
FileMapSource::FileMapSource(const AbsPath& filepath, uint64_t start, size_t size)
FileMapSource::FileMapSource(AbsPathView filepath, uint64_t start, size_t size)
{
std::error_code error;
mio::ummap_source mmap;
+6 -4
View File
@@ -45,7 +45,7 @@ namespace fs
{
//////////////////////////////////////////////////////////////////////////
FileSink::FileSink(const AbsPath& filepath, Mode mode, Flags flags) noexcept
FileSink::FileSink(AbsPathView filepath, Mode mode, Flags flags) noexcept
{
fast_io::open_mode fmode = fast_io::open_mode::out;
@@ -53,14 +53,16 @@ FileSink::FileSink(const AbsPath& filepath, Mode mode, Flags flags) noexcept
{
case Mode::CreateOrOpen:
fmode |= fast_io::open_mode::creat;
// fall through
break;
case Mode::Open:
break;
case Mode::CreateOrOpenAndClear:
fmode |= fast_io::open_mode::creat;
// fall through
//fmode |= fast_io::open_mode::creat; //cannot pass this, seems like a bug in fast_io. If it's passed, the mode reverts to OPEN_ALWAYS
fmode |= fast_io::open_mode::trunc;
break;
case Mode::OpenAndClear:
fmode |= fast_io::open_mode::trunc;
fmode |= fast_io::open_mode::excl;
break;
case Mode::CreateIfNew:
fmode |= fast_io::open_mode::creat;
+4 -4
View File
@@ -18,9 +18,9 @@ namespace fs
namespace native_utils
{
extern int validateCaseSensitiveFilename(const AbsPath& filepath, int fd);
extern int validateCaseSensitiveFilename(AbsPathView filepath, int fd);
#if defined (TL_PLATFORM_WINDOWS_FAMILY)
extern int validateCaseSensitiveFilename(const AbsPath& filepath, HANDLE handle);
extern int validateCaseSensitiveFilename(AbsPathView filepath, HANDLE handle);
#endif
}
@@ -74,14 +74,14 @@ FileSource& FileSource::operator=(FileSource&& other) noexcept
//////////////////////////////////////////////////////////////////////////
FileSource::FileSource(const AbsPath& filepath) noexcept
FileSource::FileSource(AbsPathView filepath) noexcept
: FileSource(filepath, Flags())
{
}
//////////////////////////////////////////////////////////////////////////
FileSource::FileSource(const AbsPath& filepath, Flags flags) noexcept
FileSource::FileSource(AbsPathView filepath, Flags flags) noexcept
{
const tl::string pathStr = filepath.str();
+13 -13
View File
@@ -9,7 +9,7 @@ namespace fs
{
//////////////////////////////////////////////////////////////////////////
FolderPack::FolderPack(AbsPath location)
FolderPack::FolderPack(AbsPathView location)
: m_filesystem(tl::lend(native))
, m_location(std::move(location))
{
@@ -19,7 +19,7 @@ FolderPack::FolderPack(AbsPath location)
//////////////////////////////////////////////////////////////////////////
FolderPack::FolderPack(tl::lent_ref<IFilesystem> filesystem, AbsPath location)
FolderPack::FolderPack(tl::lent_ref<IFilesystem> filesystem, AbsPathView location)
: m_filesystem(std::move(filesystem))
, m_location(std::move(location))
{
@@ -29,56 +29,56 @@ FolderPack::FolderPack(tl::lent_ref<IFilesystem> filesystem, AbsPath location)
//////////////////////////////////////////////////////////////////////////
OpenSourceResult FolderPack::openSource(const AbsPath& path, SourceFlags flags) const
OpenSourceResult FolderPack::openSource(AbsPathView path, SourceFlags flags) const
{
return m_filesystem->openSource(convertToUnderlyingPath(path), flags);
}
//////////////////////////////////////////////////////////////////////////
OpenStreamSourceResult FolderPack::openStreamSource(const AbsPath& path, SourceFlags flags) const
OpenStreamSourceResult FolderPack::openStreamSource(AbsPathView path, SourceFlags flags) const
{
return m_filesystem->openStreamSource(convertToUnderlyingPath(path), flags);
}
//////////////////////////////////////////////////////////////////////////
OpenMapSourceResult FolderPack::openMapSource(const AbsPath& path, MapView mapView, SourceFlags flags) const
OpenMapSourceResult FolderPack::openMapSource(AbsPathView path, MapView mapView, SourceFlags flags) const
{
return m_filesystem->openMapSource(convertToUnderlyingPath(path), mapView, flags);
}
//////////////////////////////////////////////////////////////////////////
IsFileResult FolderPack::isFile(const AbsPath& path) const
IsFileResult FolderPack::isFile(AbsPathView path) const
{
return m_filesystem->isFile(convertToUnderlyingPath(path));
}
//////////////////////////////////////////////////////////////////////////
IsFolderResult FolderPack::isFolder(const AbsPath& path) const
IsFolderResult FolderPack::isFolder(AbsPathView path) const
{
return m_filesystem->isFolder(convertToUnderlyingPath(path));
}
//////////////////////////////////////////////////////////////////////////
ExistsResult FolderPack::exists(const AbsPath& path) const
ExistsResult FolderPack::exists(AbsPathView path) const
{
return m_filesystem->exists(convertToUnderlyingPath(path));
}
//////////////////////////////////////////////////////////////////////////
GetStatResult FolderPack::getStat(const AbsPath& path) const
GetStatResult FolderPack::getStat(AbsPathView path) const
{
return m_filesystem->getStat(convertToUnderlyingPath(path));
}
//////////////////////////////////////////////////////////////////////////
cppcoro::generator<EnumerateEntry> FolderPack::enumerate(const AbsPath& path) const
cppcoro::generator<EnumerateEntry> FolderPack::enumerate(AbsPath path) const
{
const AbsPath localPath = convertToUnderlyingPath(path);
for (EnumerateEntry ee : m_filesystem->enumerate(localPath))
@@ -87,7 +87,7 @@ cppcoro::generator<EnumerateEntry> FolderPack::enumerate(const AbsPath& path) co
//////////////////////////////////////////////////////////////////////////
cppcoro::generator<EnumerateEntry> FolderPack::enumerateRecursively(const AbsPath& path) const
cppcoro::generator<EnumerateEntry> FolderPack::enumerateRecursively(AbsPath path) const
{
const AbsPath localPath = convertToUnderlyingPath(path);
for (EnumerateEntry ee : m_filesystem->enumerateRecursively(localPath))
@@ -96,7 +96,7 @@ cppcoro::generator<EnumerateEntry> FolderPack::enumerateRecursively(const AbsPat
//////////////////////////////////////////////////////////////////////////
AbsPath FolderPack::convertToUnderlyingPath(const AbsPath& path) const
AbsPath FolderPack::convertToUnderlyingPath(AbsPathView path) const
{
AbsPath filePath;
filePath.reserve(m_location.size() + path.size());
@@ -109,7 +109,7 @@ AbsPath FolderPack::convertToUnderlyingPath(const AbsPath& path) const
//////////////////////////////////////////////////////////////////////////
ConvertToNativePathResult FolderPack::convertToNativePath(const AbsPath& path) const
ConvertToNativePathResult FolderPack::convertToNativePath(AbsPathView path) const
{
return m_filesystem->convertToNativePath(convertToUnderlyingPath(path));
}
+26 -25
View File
@@ -28,7 +28,7 @@ FS_API NativeFilesystem native(NativeFilesystem::CheckFlag::ValidatePathCase);
FS_API NativeFilesystem nativeRaw;
//////////////////////////////////////////////////////////////////////////
std::filesystem::path toStdPath(const AbsPath& path) noexcept
std::filesystem::path toStdPath(AbsPathView path) noexcept
{
const tl::string str = path.str();
return { str.data(), str.data() + str.size() };
@@ -124,7 +124,7 @@ NativeFilesystem::NativeFilesystem(CheckFlags checkFlags)
//////////////////////////////////////////////////////////////////////////
OpenSourceResult NativeFilesystem::openSource(const AbsPath& path, SourceFlags flags) const
OpenSourceResult NativeFilesystem::openSource(AbsPathView path, SourceFlags flags) const
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -158,7 +158,7 @@ OpenSourceResult NativeFilesystem::openSource(const AbsPath& path, SourceFlags f
//////////////////////////////////////////////////////////////////////////
OpenStreamSourceResult NativeFilesystem::openStreamSource(const AbsPath& path, SourceFlags flags) const
OpenStreamSourceResult NativeFilesystem::openStreamSource(AbsPathView path, SourceFlags flags) const
{
OUTCOME_TRY(auto source, openSource(path, flags));
return source;
@@ -166,7 +166,7 @@ OpenStreamSourceResult NativeFilesystem::openStreamSource(const AbsPath& path, S
//////////////////////////////////////////////////////////////////////////
OpenMapSourceResult NativeFilesystem::openMapSource(const AbsPath& path, MapView mapView, SourceFlags flags) const
OpenMapSourceResult NativeFilesystem::openMapSource(AbsPathView path, MapView mapView, SourceFlags flags) const
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -184,7 +184,7 @@ OpenMapSourceResult NativeFilesystem::openMapSource(const AbsPath& path, MapView
//////////////////////////////////////////////////////////////////////////
OpenSinkResult NativeFilesystem::openSink(const AbsPath& path, Mode mode, SinkFlags flags)
OpenSinkResult NativeFilesystem::openSink(AbsPathView path, Mode mode, SinkFlags flags)
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -202,7 +202,7 @@ OpenSinkResult NativeFilesystem::openSink(const AbsPath& path, Mode mode, SinkFl
//////////////////////////////////////////////////////////////////////////
OpenStreamSinkResult NativeFilesystem::openStreamSink(const AbsPath& path, Mode mode, SinkFlags flags)
OpenStreamSinkResult NativeFilesystem::openStreamSink(AbsPathView path, Mode mode, SinkFlags flags)
{
OUTCOME_TRY(auto source, openSink(path, mode, flags));
return source;
@@ -210,7 +210,7 @@ OpenStreamSinkResult NativeFilesystem::openStreamSink(const AbsPath& path, Mode
//////////////////////////////////////////////////////////////////////////
OpenMapSinkResult NativeFilesystem::openMapSink(const AbsPath& path, Mode mode, size_t size, SinkFlags flags)
OpenMapSinkResult NativeFilesystem::openMapSink(AbsPathView path, Mode mode, size_t size, SinkFlags flags)
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -228,14 +228,14 @@ OpenMapSinkResult NativeFilesystem::openMapSink(const AbsPath& path, Mode mode,
//////////////////////////////////////////////////////////////////////////
ConvertToNativePathResult NativeFilesystem::convertToNativePath(const AbsPath& path) const
ConvertToNativePathResult NativeFilesystem::convertToNativePath(AbsPathView path) const
{
return path;
}
//////////////////////////////////////////////////////////////////////////
ExistsResult NativeFilesystem::exists(const AbsPath& path) const
ExistsResult NativeFilesystem::exists(AbsPathView path) const
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -255,7 +255,7 @@ ExistsResult NativeFilesystem::exists(const AbsPath& path) const
//////////////////////////////////////////////////////////////////////////
IsFileResult NativeFilesystem::isFile(const AbsPath& path) const
IsFileResult NativeFilesystem::isFile(AbsPathView path) const
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -277,7 +277,7 @@ IsFileResult NativeFilesystem::isFile(const AbsPath& path) const
//////////////////////////////////////////////////////////////////////////
IsFolderResult NativeFilesystem::isFolder(const AbsPath& path) const
IsFolderResult NativeFilesystem::isFolder(AbsPathView path) const
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -299,7 +299,7 @@ IsFolderResult NativeFilesystem::isFolder(const AbsPath& path) const
//////////////////////////////////////////////////////////////////////////
RenameResult NativeFilesystem::rename(const AbsPath& path, const AbsPath& newPath)
RenameResult NativeFilesystem::rename(AbsPathView path, AbsPathView newPath)
{
if (!path.is_valid() || !newPath.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -321,7 +321,7 @@ RenameResult NativeFilesystem::rename(const AbsPath& path, const AbsPath& newPat
//////////////////////////////////////////////////////////////////////////
CopyResult NativeFilesystem::copy(const AbsPath& path, const AbsPath& newPath)
CopyResult NativeFilesystem::copy(AbsPathView path, AbsPathView newPath)
{
if (!path.is_valid() || !newPath.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -345,7 +345,7 @@ CopyResult NativeFilesystem::copy(const AbsPath& path, const AbsPath& newPath)
//////////////////////////////////////////////////////////////////////////
MakeHardLinkResult NativeFilesystem::makeHardLink(const AbsPath& sourcePath, const AbsPath& linkPath)
MakeHardLinkResult NativeFilesystem::makeHardLink(AbsPathView sourcePath, AbsPathView linkPath)
{
if (!sourcePath.is_valid() || !linkPath.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -368,7 +368,7 @@ MakeHardLinkResult NativeFilesystem::makeHardLink(const AbsPath& sourcePath, con
//////////////////////////////////////////////////////////////////////////
MakeSoftLinkResult NativeFilesystem::makeSymLink(const AbsPath& sourcePath, const AbsPath& linkPath)
MakeSoftLinkResult NativeFilesystem::makeSymLink(AbsPathView sourcePath, AbsPathView linkPath)
{
if (!sourcePath.is_valid() || !linkPath.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -397,7 +397,7 @@ MakeSoftLinkResult NativeFilesystem::makeSymLink(const AbsPath& sourcePath, cons
//////////////////////////////////////////////////////////////////////////
MakeFolderResult NativeFilesystem::makeFolder(const AbsPath& path)
MakeFolderResult NativeFilesystem::makeFolder(AbsPathView path)
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -423,7 +423,7 @@ MakeFolderResult NativeFilesystem::makeFolder(const AbsPath& path)
//////////////////////////////////////////////////////////////////////////
RemoveResult NativeFilesystem::remove(const AbsPath& path)
RemoveResult NativeFilesystem::remove(AbsPathView path)
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -445,7 +445,7 @@ RemoveResult NativeFilesystem::remove(const AbsPath& path)
//////////////////////////////////////////////////////////////////////////
RemoveRecursivelyResult NativeFilesystem::removeRecursively(const AbsPath& path)
RemoveRecursivelyResult NativeFilesystem::removeRecursively(AbsPathView path)
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -472,7 +472,7 @@ RemoveRecursivelyResult NativeFilesystem::removeRecursively(const AbsPath& path)
//////////////////////////////////////////////////////////////////////////
SetWriteTimeResult NativeFilesystem::setWriteTime(const AbsPath& path, time_t time)
SetWriteTimeResult NativeFilesystem::setWriteTime(AbsPathView path, time_t time)
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -499,7 +499,7 @@ SetWriteTimeResult NativeFilesystem::setWriteTime(const AbsPath& path, time_t ti
//////////////////////////////////////////////////////////////////////////
GetStatResult NativeFilesystem::getStat(const AbsPath& path) const
GetStatResult NativeFilesystem::getStat(AbsPathView path) const
{
if (!path.is_valid())
return tl::make_error<Error>(ErrorCode::BadPath, "Invalid Path");
@@ -522,7 +522,7 @@ GetStatResult NativeFilesystem::getStat(const AbsPath& path) const
//////////////////////////////////////////////////////////////////////////
cppcoro::generator<EnumerateEntry> NativeFilesystem::enumerate(const AbsPath& path) const
cppcoro::generator<EnumerateEntry> NativeFilesystem::enumerate(AbsPath path) const
{
TL_ASSERT(path.is_valid());
@@ -555,7 +555,7 @@ cppcoro::generator<EnumerateEntry> NativeFilesystem::enumerate(const AbsPath& pa
//////////////////////////////////////////////////////////////////////////
cppcoro::generator<EnumerateEntry> NativeFilesystem::enumerateRecursively(const AbsPath& path) const
cppcoro::generator<EnumerateEntry> NativeFilesystem::enumerateRecursively(AbsPath path) const
{
TL_ASSERT(path.is_valid());
@@ -571,6 +571,7 @@ cppcoro::generator<EnumerateEntry> NativeFilesystem::enumerateRecursively(const
AbsPath eePath;
const auto stdRootPath = toStdPath(path);
for (auto const& entry : std::filesystem::recursive_directory_iterator{ stdRootPath })
{
const auto status = entry.status();
@@ -599,7 +600,7 @@ AbsPath NativeFilesystem::getCurrentFolder() const
//////////////////////////////////////////////////////////////////////////
tl::result<Error> NativeFilesystem::setCurrentFolder(const AbsPath& path)
tl::result<Error> NativeFilesystem::setCurrentFolder(AbsPathView path)
{
if (!path.is_valid())
return tl::make_error<Error>(Error::code_t::BadPath, "Path empty");
@@ -621,7 +622,7 @@ tl::result<Error> NativeFilesystem::setCurrentFolder(const AbsPath& path)
//////////////////////////////////////////////////////////////////////////
NativeFilesystem::EnumerateFilesResult NativeFilesystem::enumerateFiles(const AbsPath& fullPath) const
NativeFilesystem::EnumerateFilesResult NativeFilesystem::enumerateFiles(AbsPathView fullPath) const
{
tl::vector<tl::string> files;
for (EnumerateEntry ee: enumerate(fullPath))
@@ -637,7 +638,7 @@ NativeFilesystem::EnumerateFilesResult NativeFilesystem::enumerateFiles(const Ab
//////////////////////////////////////////////////////////////////////////
NativeFilesystem::EnumerateFoldersResult NativeFilesystem::enumerateFolders(const AbsPath& fullPath) const
NativeFilesystem::EnumerateFoldersResult NativeFilesystem::enumerateFolders(AbsPathView fullPath) const
{
tl::vector<tl::string> folders;
for (EnumerateEntry ee : enumerate(fullPath))
+7 -7
View File
@@ -62,14 +62,14 @@ bool isCapitalizationCorrect(const tl::string& str, HANDLE handle) noexcept
//////////////////////////////////////////////////////////////////////////
bool isCapitalizationCorrect(const AbsPath& path, HANDLE handle) noexcept
bool isCapitalizationCorrect(AbsPathView path, HANDLE handle) noexcept
{
return isCapitalizationCorrect(path.str(), handle);
}
//////////////////////////////////////////////////////////////////////////
static bool isFileCapitalizationCorrect(const AbsPath& filePath) noexcept
static bool isFileCapitalizationCorrect(AbsPathView filePath) noexcept
{
const tl::string fileStr = filePath.str();
const char* fileName = fileStr.c_str();
@@ -90,7 +90,7 @@ static bool isFileCapitalizationCorrect(const AbsPath& filePath) noexcept
//////////////////////////////////////////////////////////////////////////
static bool isFolderCapitalizationCorrect(const AbsPath& folderPath) noexcept
static bool isFolderCapitalizationCorrect(AbsPathView folderPath) noexcept
{
const tl::string folderStr = folderPath.str();
const char* folderName = folderStr.c_str();
@@ -116,7 +116,7 @@ static bool isFolderCapitalizationCorrect(const AbsPath& folderPath) noexcept
//////////////////////////////////////////////////////////////////////////
bool validateCaseSensitiveFilename(const AbsPath& filepath) noexcept
bool validateCaseSensitiveFilename(AbsPathView filepath) noexcept
{
#ifdef TL_PLATFORM_WINDOWS_DESKTOP_APP
return isFileCapitalizationCorrect(filepath);
@@ -127,7 +127,7 @@ bool validateCaseSensitiveFilename(const AbsPath& filepath) noexcept
//////////////////////////////////////////////////////////////////////////
bool validateCaseSensitiveFilename(const AbsPath& filepath, int fd) noexcept
bool validateCaseSensitiveFilename(AbsPathView filepath, int fd) noexcept
{
#ifdef TL_PLATFORM_WINDOWS_DESKTOP_APP
const HANDLE handle = (HANDLE)_get_osfhandle(fd);
@@ -143,7 +143,7 @@ bool validateCaseSensitiveFilename(const AbsPath& filepath, int fd) noexcept
//////////////////////////////////////////////////////////////////////////
#ifdef TL_PLATFORM_WINDOWS_FAMILY
bool validateCaseSensitiveFilename(const AbsPath& filepath, HANDLE handle) noexcept
bool validateCaseSensitiveFilename(AbsPathView filepath, HANDLE handle) noexcept
{
#ifdef TL_PLATFORM_WINDOWS_DESKTOP_APP
if (handle == INVALID_HANDLE_VALUE)
@@ -157,7 +157,7 @@ bool validateCaseSensitiveFilename(const AbsPath& filepath, HANDLE handle) noexc
#endif
//////////////////////////////////////////////////////////////////////////
bool validateCaseSensitiveFolder(const AbsPath& folderPath) noexcept
bool validateCaseSensitiveFolder(AbsPathView folderPath) noexcept
{
#ifdef TL_PLATFORM_WINDOWS_DESKTOP_APP
return isFolderCapitalizationCorrect(folderPath);
+3 -3
View File
@@ -98,7 +98,7 @@ ReadStreamResult readStream(std::string& buffer, IStreamSource& source, size_t b
//////////////////////////////////////////////////////////////////////////
ReadStreamResult readFile(tl::memory_buffer& buffer, IFilesystem& filesystem, const AbsPath& filePath, size_t bufferSize)
ReadStreamResult readFile(tl::memory_buffer& buffer, IFilesystem& filesystem, AbsPathView filePath, size_t bufferSize)
{
OUTCOME_TRY(const auto source, filesystem.openStreamSource(filePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return readStream(buffer, *source, bufferSize);
@@ -106,7 +106,7 @@ ReadStreamResult readFile(tl::memory_buffer& buffer, IFilesystem& filesystem, co
//////////////////////////////////////////////////////////////////////////
ReadStreamResult readFile(eastl::string& buffer, IFilesystem& filesystem, const AbsPath& filePath, size_t bufferSize)
ReadStreamResult readFile(eastl::string& buffer, IFilesystem& filesystem, AbsPathView filePath, size_t bufferSize)
{
OUTCOME_TRY(const auto source, filesystem.openStreamSource(filePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return readStream(buffer, *source, bufferSize);
@@ -114,7 +114,7 @@ ReadStreamResult readFile(eastl::string& buffer, IFilesystem& filesystem, const
//////////////////////////////////////////////////////////////////////////
ReadStreamResult readFile(std::string& buffer, IFilesystem& filesystem, const AbsPath& filePath, size_t bufferSize)
ReadStreamResult readFile(std::string& buffer, IFilesystem& filesystem, AbsPathView filePath, size_t bufferSize)
{
OUTCOME_TRY(const auto source, filesystem.openStreamSource(filePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return readStream(buffer, *source, bufferSize);
@@ -1,9 +1,10 @@
#include "StdAfx.h"
#include "fs/StreamSourceToSourceAdapter.h"
#include "fs/StreamSourceToMapSourceAdapter.h"
#include <algorithm>
#include "fs/ReadStream.h"
#include "tl/narrow_cast.h"
namespace fs
@@ -12,21 +13,21 @@ namespace fs
static constexpr size_t k_chunkSize = 10 * 1024;
StreamSourceToSourceAdapter::StreamSourceToSourceAdapter(tl::unique_ref<IStreamSource>&& srcSource)
StreamSourceToMapSourceAdapter::StreamSourceToMapSourceAdapter(tl::unique_ref<IStreamSource> srcSource)
: m_srcSource(std::move(srcSource))
{
}
//////////////////////////////////////////////////////////////////////////
tl::optional<Error> StreamSourceToSourceAdapter::getLastError() const
tl::optional<Error> StreamSourceToMapSourceAdapter::getLastError() const
{
return m_optLastError;
}
//////////////////////////////////////////////////////////////////////////
size_t StreamSourceToSourceAdapter::read(tl::span<uint8_t> data)
size_t StreamSourceToMapSourceAdapter::read(tl::span<uint8_t> data)
{
if (m_optLastError.has_value())
{
@@ -69,7 +70,7 @@ size_t StreamSourceToSourceAdapter::read(tl::span<uint8_t> data)
//////////////////////////////////////////////////////////////////////////
void StreamSourceToSourceAdapter::seekBeg(uint64_t offset)
void StreamSourceToMapSourceAdapter::seekBeg(uint64_t offset)
{
if (m_optLastError.has_value())
{
@@ -88,7 +89,7 @@ void StreamSourceToSourceAdapter::seekBeg(uint64_t offset)
//////////////////////////////////////////////////////////////////////////
void StreamSourceToSourceAdapter::seekRel(int64_t offset)
void StreamSourceToMapSourceAdapter::seekRel(int64_t offset)
{
if (m_optLastError.has_value())
{
@@ -107,7 +108,7 @@ void StreamSourceToSourceAdapter::seekRel(int64_t offset)
//////////////////////////////////////////////////////////////////////////
uint64_t StreamSourceToSourceAdapter::tell() const
uint64_t StreamSourceToMapSourceAdapter::tell() const
{
if (m_optLastError.has_value())
{
@@ -120,7 +121,7 @@ uint64_t StreamSourceToSourceAdapter::tell() const
//////////////////////////////////////////////////////////////////////////
uint64_t StreamSourceToSourceAdapter::getSize() const
uint64_t StreamSourceToMapSourceAdapter::getSize() const
{
if (m_optLastError.has_value())
{
@@ -137,7 +138,7 @@ uint64_t StreamSourceToSourceAdapter::getSize() const
//////////////////////////////////////////////////////////////////////////
bool StreamSourceToSourceAdapter::isEOS() const
bool StreamSourceToMapSourceAdapter::isEOS() const
{
if (m_optLastError.has_value())
{
@@ -156,14 +157,14 @@ bool StreamSourceToSourceAdapter::isEOS() const
//////////////////////////////////////////////////////////////////////////
size_t StreamSourceToSourceAdapter::getPreferredBufferSize() const
size_t StreamSourceToMapSourceAdapter::getPreferredBufferSize() const
{
return m_srcSource->getPreferredBufferSize();
}
//////////////////////////////////////////////////////////////////////////
tl::span<const uint8_t> StreamSourceToSourceAdapter::map(size_t size)
tl::span<const uint8_t> StreamSourceToMapSourceAdapter::map(size_t size)
{
if (m_optLastError.has_value())
{
@@ -189,34 +190,20 @@ tl::span<const uint8_t> StreamSourceToSourceAdapter::map(size_t size)
//////////////////////////////////////////////////////////////////////////
void StreamSourceToSourceAdapter::readAll() const
void StreamSourceToMapSourceAdapter::readAll() const
{
if (m_readAll)
return;
const size_t chunkSize = m_srcSource->getPreferredBufferSize() > 0 ? m_srcSource->getPreferredBufferSize() : k_chunkSize;
do
if (!m_readAll)
{
const size_t dataSize = m_data.size();
m_data.resize_uninitialized(dataSize + chunkSize);
const uint64_t read = m_srcSource->read({ m_data.data() + dataSize, chunkSize });
if (read < chunkSize || m_srcSource->isEOS())
{
m_data.resize_uninitialized(dataSize + tl::narrow<size_t>(read));
break;
}
m_optLastError = m_srcSource->getLastError();
if (m_optLastError != tl::nullopt)
if (auto readResult = fs::readStream(m_data, *m_srcSource); readResult.has_error())
{
m_optLastError = readResult.error();
m_data.clear();
break;
}
} while (true);
m_data.shrink_to_fit();
m_readAll = true;
}
}
//////////////////////////////////////////////////////////////////////////
}
+10 -10
View File
@@ -7,7 +7,7 @@ namespace fs
{
//////////////////////////////////////////////////////////////////////////
WritableFolderPack::WritableFolderPack(AbsPath location)
WritableFolderPack::WritableFolderPack(AbsPathView location)
: FolderPack(std::move(location))
{
MakeFolderResult result = fs::native.makeFolder(m_location);
@@ -17,7 +17,7 @@ WritableFolderPack::WritableFolderPack(AbsPath location)
//////////////////////////////////////////////////////////////////////////
WritableFolderPack::WritableFolderPack(tl::lent_ref<IFilesystem> filesystem, AbsPath location)
WritableFolderPack::WritableFolderPack(tl::lent_ref<IFilesystem> filesystem, AbsPathView location)
: FolderPack(std::move(filesystem), std::move(location))
{
MakeFolderResult result = m_filesystem->makeFolder(m_location);
@@ -27,7 +27,7 @@ WritableFolderPack::WritableFolderPack(tl::lent_ref<IFilesystem> filesystem, Abs
//////////////////////////////////////////////////////////////////////////
OpenSinkResult WritableFolderPack::openSink(const AbsPath& path, Mode mode, SinkFlags flags)
OpenSinkResult WritableFolderPack::openSink(AbsPathView path, Mode mode, SinkFlags flags)
{
OUTCOME_TRY(const auto npath, convertToNativePath(path));
return m_filesystem->openSink(npath, mode, flags);
@@ -35,7 +35,7 @@ OpenSinkResult WritableFolderPack::openSink(const AbsPath& path, Mode mode, Sink
//////////////////////////////////////////////////////////////////////////
OpenStreamSinkResult WritableFolderPack::openStreamSink(const AbsPath& path, Mode mode, SinkFlags flags)
OpenStreamSinkResult WritableFolderPack::openStreamSink(AbsPathView path, Mode mode, SinkFlags flags)
{
OUTCOME_TRY(const auto npath, convertToNativePath(path));
return m_filesystem->openStreamSink(npath, mode, flags);
@@ -43,7 +43,7 @@ OpenStreamSinkResult WritableFolderPack::openStreamSink(const AbsPath& path, Mod
//////////////////////////////////////////////////////////////////////////
OpenMapSinkResult WritableFolderPack::openMapSink(const AbsPath& path, Mode mode, size_t size, SinkFlags flags)
OpenMapSinkResult WritableFolderPack::openMapSink(AbsPathView path, Mode mode, size_t size, SinkFlags flags)
{
OUTCOME_TRY(const auto npath, convertToNativePath(path));
return m_filesystem->openMapSink(npath, mode, size, flags);
@@ -51,7 +51,7 @@ OpenMapSinkResult WritableFolderPack::openMapSink(const AbsPath& path, Mode mode
//////////////////////////////////////////////////////////////////////////
RemoveResult WritableFolderPack::remove(const AbsPath& path)
RemoveResult WritableFolderPack::remove(AbsPathView path)
{
OUTCOME_TRY(const auto npath, convertToNativePath(path));
return m_filesystem->remove(npath);
@@ -59,7 +59,7 @@ RemoveResult WritableFolderPack::remove(const AbsPath& path)
//////////////////////////////////////////////////////////////////////////
RenameResult WritableFolderPack::rename(const AbsPath& path, const AbsPath& newPath)
RenameResult WritableFolderPack::rename(AbsPathView path, AbsPathView newPath)
{
OUTCOME_TRY(const auto filePath, convertToNativePath(path));
OUTCOME_TRY(const auto newFilePath, convertToNativePath(newPath));
@@ -68,7 +68,7 @@ RenameResult WritableFolderPack::rename(const AbsPath& path, const AbsPath& newP
//////////////////////////////////////////////////////////////////////////
MakeFolderResult WritableFolderPack::makeFolder(const AbsPath& path)
MakeFolderResult WritableFolderPack::makeFolder(AbsPathView path)
{
OUTCOME_TRY(const auto npath, convertToNativePath(path));
return m_filesystem->makeFolder(npath);
@@ -76,7 +76,7 @@ MakeFolderResult WritableFolderPack::makeFolder(const AbsPath& path)
//////////////////////////////////////////////////////////////////////////
RemoveRecursivelyResult WritableFolderPack::removeRecursively(const AbsPath& path)
RemoveRecursivelyResult WritableFolderPack::removeRecursively(AbsPathView path)
{
OUTCOME_TRY(const auto npath, convertToNativePath(path));
return m_filesystem->removeRecursively(npath);
@@ -84,7 +84,7 @@ RemoveRecursivelyResult WritableFolderPack::removeRecursively(const AbsPath& pat
//////////////////////////////////////////////////////////////////////////
SetWriteTimeResult WritableFolderPack::setWriteTime(const AbsPath& path, time_t time)
SetWriteTimeResult WritableFolderPack::setWriteTime(AbsPathView path, time_t time)
{
OUTCOME_TRY(const auto npath, convertToNativePath(path));
return m_filesystem->setWriteTime(npath, time);
+4
View File
@@ -0,0 +1,4 @@
root = true
[*]
insert_final_newline = true
+7
View File
@@ -0,0 +1,7 @@
# editorconfig
321f2fa166c804c1ddb0aa5cf9afc8cde7e3be43
# clang-format
395c9c7f67771c64ae673caa1428f848fd8242e7
458c2f98c9fee122dd01e04d73b76786b13498d0
b9db56983496403e8cdd065c6d9e5300eccb05b2
e3c089ffca7836c3d7d3a022afbbc0f98010a946
+15
View File
@@ -0,0 +1,15 @@
*.exe
benchmarks/*/*.txt
*/build/*
!.cc
*.app
/include/.vscode
/include/fast_io_network/.vscode/settings.json
.tmp
.vscode
build
.vs/
.*/*
*.obj
*.html
*.txt
+562
View File
@@ -0,0 +1,562 @@
#pragma once
#if !defined(__cplusplus)
#error "You are not using a C++ compiler"
#endif
#if !defined(__cpp_concepts)
#error "fast_io requires at least C++20 standard compiler."
#else
#include"fast_io_hosted.h"
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
#pragma warning( disable : 4514 )
#endif
#if ((__STDC_HOSTED__==1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED==1) && !defined(_LIBCPP_FREESTANDING)) || defined(FAST_IO_ENABLE_HOSTED_FEATURES))
#if __has_include(<stdio.h>)
#include"fast_io_legacy_impl/c/impl.h"
#endif
namespace fast_io
{
#if !defined(__AVR__)
inline
#if defined(__WINE__) || !defined(_WIN32)
constexpr
#endif
native_io_observer in() noexcept
{
return native_stdin();
}
inline
#if defined(__WINE__) || !defined(_WIN32)
constexpr
#endif
native_io_observer out() noexcept
{
return native_stdout();
}
inline
#if defined(__WINE__) || !defined(_WIN32)
constexpr
#endif
native_io_observer err() noexcept
{
return native_stderr();
}
inline
#if defined(__WINE__) || !defined(_WIN32)
constexpr
#endif
decltype(auto) u8in() noexcept
{
return native_stdin<char8_t>();
}
inline
#if defined(__WINE__) || !defined(_WIN32)
constexpr
#endif
decltype(auto) u8out() noexcept
{
return native_stdout<char8_t>();
}
inline
#if defined(__WINE__) || !defined(_WIN32)
constexpr
#endif
decltype(auto) u8err() noexcept
{
return native_stderr<char8_t>();
}
using in_buf_type = basic_ibuf<native_io_observer>;
using out_buf_type = basic_obuf<native_io_observer>;
using u8in_buf_type = basic_ibuf<u8native_io_observer>;
using u8out_buf_type = basic_obuf<u8native_io_observer>;
using in_buf_type_mutex = basic_iomutex<in_buf_type>;
using out_buf_type_mutex = basic_iomutex<out_buf_type>;
using u8in_buf_type_mutex = basic_iomutex<u8in_buf_type>;
using u8out_buf_type_mutex = basic_iomutex<u8out_buf_type>;
#if defined(_WIN32) || defined(__CYGWIN__)
inline constexpr basic_win32_box_t<char> box() noexcept
{
return basic_win32_box_t<char>{};
}
inline constexpr basic_win32_box_t<wchar_t> wbox() noexcept
{
return basic_win32_box_t<wchar_t>{};
}
inline constexpr basic_win32_box_t<char8_t> u8box() noexcept
{
return basic_win32_box_t<char8_t>{};
}
inline constexpr basic_win32_box_t<char16_t> u16box() noexcept
{
return basic_win32_box_t<char16_t>{};
}
inline constexpr basic_win32_box_t<char32_t> u32box() noexcept
{
return basic_win32_box_t<char32_t>{};
}
#else
inline
#ifndef _WIN32
constexpr
#endif
decltype(auto) box() noexcept
{
return native_stdout<char>();
}
inline
#ifndef _WIN32
constexpr
#endif
decltype(auto) wbox() noexcept
{
return native_stdout<wchar_t>();
}
inline
#ifndef _WIN32
constexpr
#endif
decltype(auto) u8box() noexcept
{
return native_stdout<char8_t>();
}
inline
#ifndef _WIN32
constexpr
#endif
decltype(auto) u16box() noexcept
{
return native_stdout<char16_t>();
}
inline
#ifndef _WIN32
constexpr
#endif
decltype(auto) u32box() noexcept
{
return native_stdout<char32_t>();
}
#endif
#endif
namespace details
{
template<bool line,typename... Args>
inline constexpr void print_after_io_print_forward(Args ...args)
{
#if __has_include(<stdio.h>)
print_freestanding_decay<line>(c_stdout(),args...);
#else
print_freestanding_decay<line>(out(),args...);
#endif
}
template<bool line,typename... Args>
#if __has_cpp_attribute(__gnu__::__cold__)
[[__gnu__::__cold__]]
#endif
inline constexpr void perr_after_io_print_forward(Args ...args)
{
#if defined(__AVR__)
print_freestanding_decay<line>(c_stderr(),args...);
#else
print_freestanding_decay<line>(err(),args...);
#endif
}
template<bool line,typename... Args>
#if __has_cpp_attribute(__gnu__::__cold__)
[[__gnu__::__cold__]]
#endif
inline constexpr void debug_print_after_io_print_forward(Args ...args)
{
#if defined(__AVR__)
print_freestanding_decay<line>(c_stdout(),args...);
#else
print_freestanding_decay<line>(out(),args...);
#endif
}
template<bool report,typename... Args>
inline constexpr std::conditional_t<report,bool,void> scan_after_io_scan_forward(Args ...args)
{
#if __has_include(<stdio.h>)
if constexpr(report)
return scan_freestanding_decay(c_stdin(),args...);
else
{
if(!scan_freestanding_decay(c_stdin(),args...))
::fast_io::throw_parse_code(fast_io::parse_code::end_of_file);
}
#else
if constexpr(report)
return scan_freestanding_decay(in(),args...);
else
{
if(!scan_freestanding_decay(in(),args...))
::fast_io::throw_parse_code(fast_io::parse_code::end_of_file);
}
#endif
}
}
}
#endif
namespace fast_io::io
{
template<typename T,typename... Args>
inline constexpr void print(T&& t,Args&& ...args)
{
constexpr bool device_error{fast_io::output_stream<std::remove_cvref_t<T>>||fast_io::status_output_stream<std::remove_cvref_t<T>>};
if constexpr(device_error)
{
constexpr bool type_error{::fast_io::print_freestanding_okay<T,Args...>};
if constexpr(type_error)
{
::fast_io::print_freestanding_decay<false>(fast_io::io_ref(t),::fast_io::io_print_forward<typename ::std::remove_cvref_t<T>::char_type>(::fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for print");
}
}
else
{
#if ((__STDC_HOSTED__==1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED==1) && !defined(_LIBCPP_FREESTANDING)) || defined(FAST_IO_ENABLE_HOSTED_FEATURES)) && __has_include(<stdio.h>)
constexpr bool type_error{::fast_io::print_freestanding_okay<
#if __has_include(<stdio.h>)
::fast_io::c_io_observer
#else
::fast_io::native_io_observer
#endif
,T,Args...>};
if constexpr(type_error)
{
::fast_io::details::print_after_io_print_forward<false>(::fast_io::io_print_forward<char>(::fast_io::io_print_alias(t)),::fast_io::io_print_forward<char>(::fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for print on default C's stdout");
}
#else
static_assert(device_error,"freestanding environment must provide IO device for print");
#endif
}
}
template<typename T,typename... Args>
inline constexpr void println(T&& t,Args&& ...args)
{
constexpr bool device_error{fast_io::output_stream<std::remove_cvref_t<T>>||fast_io::status_output_stream<std::remove_cvref_t<T>>};
if constexpr(device_error)
{
constexpr bool type_error{::fast_io::print_freestanding_okay<T,Args...>};
if constexpr(type_error)
{
::fast_io::print_freestanding_decay<true>(fast_io::io_ref(t),fast_io::io_print_forward<typename std::remove_cvref_t<T>::char_type>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for println");
}
}
else
{
#if ((__STDC_HOSTED__==1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED==1) && !defined(_LIBCPP_FREESTANDING)) || defined(FAST_IO_ENABLE_HOSTED_FEATURES)) && __has_include(<stdio.h>)
constexpr bool type_error{::fast_io::print_freestanding_okay<
#if __has_include(<stdio.h>)
::fast_io::c_io_observer
#else
::fast_io::native_io_observer
#endif
,T,Args...>};
if constexpr(type_error)
{
::fast_io::details::print_after_io_print_forward<true>(fast_io::io_print_forward<char>(fast_io::io_print_alias(t)),fast_io::io_print_forward<char>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for println on default C's stdout");
}
#else
static_assert(device_error,"freestanding environment must provide IO device for println");
#endif
}
}
template<typename T,typename... Args>
inline constexpr void perr(T&& t,Args&&... args)
{
constexpr bool device_error{fast_io::output_stream<std::remove_cvref_t<T>>||fast_io::status_output_stream<std::remove_cvref_t<T>>};
if constexpr(device_error)
{
constexpr bool type_error{::fast_io::print_freestanding_okay<T,Args...>};
if constexpr(type_error)
{
::fast_io::print_freestanding_decay_cold<false>(fast_io::io_ref(t),fast_io::io_print_forward<typename std::remove_cvref_t<T>::char_type>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for perr");
}
}
else
{
#if ((__STDC_HOSTED__==1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED==1) && !defined(_LIBCPP_FREESTANDING)) || defined(FAST_IO_ENABLE_HOSTED_FEATURES))
constexpr bool type_error{::fast_io::print_freestanding_okay<
#if defined(__AVR__)
::fast_io::c_io_observer
#else
::fast_io::native_io_observer
#endif
,T,Args...>};
if constexpr(type_error)
{
::fast_io::details::perr_after_io_print_forward<false>(fast_io::io_print_forward<char>(fast_io::io_print_alias(t)),fast_io::io_print_forward<char>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for perr on native err");
}
#else
static_assert(device_error,"freestanding environment must provide IO device");
#endif
}
}
template<typename T,typename... Args>
inline constexpr void perrln(T&& t,Args&&... args)
{
constexpr bool device_error{fast_io::output_stream<std::remove_cvref_t<T>>||fast_io::status_output_stream<std::remove_cvref_t<T>>};
if constexpr(device_error)
{
constexpr bool type_error{::fast_io::print_freestanding_okay<T,Args...>};
if constexpr(type_error)
{
::fast_io::print_freestanding_decay_cold<true>(fast_io::io_ref(t),fast_io::io_print_forward<typename std::remove_cvref_t<T>::char_type>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for perrln");
}
}
else
{
#if ((__STDC_HOSTED__==1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED==1) && !defined(_LIBCPP_FREESTANDING)) || defined(FAST_IO_ENABLE_HOSTED_FEATURES))
constexpr bool type_error{::fast_io::print_freestanding_okay<
#if defined(__AVR__)
::fast_io::c_io_observer
#else
::fast_io::native_io_observer
#endif
,T,Args...>};
if constexpr(type_error)
{
::fast_io::details::perr_after_io_print_forward<true>(fast_io::io_print_forward<char>(fast_io::io_print_alias(t)),fast_io::io_print_forward<char>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for perrln on native err");
}
#else
static_assert(device_error,"freestanding environment must provide IO device");
#endif
}
}
template<typename... Args>
[[noreturn]] inline constexpr void panic(Args&&... args) noexcept
{
if constexpr(sizeof...(Args)!=0)
{
#ifdef __cpp_exceptions
try
{
#endif
::fast_io::io::perr(::std::forward<Args>(args)...);
#ifdef __cpp_exceptions
}
catch(...){}
#endif
}
::fast_io::fast_terminate();
}
template<typename... Args>
requires (sizeof...(Args)!=0)
[[noreturn]] inline constexpr void panicln(Args&&... args) noexcept
{
#ifdef __cpp_exceptions
try
{
#endif
::fast_io::io::perrln(::std::forward<Args>(args)...);
#ifdef __cpp_exceptions
}
catch(...){}
#endif
::fast_io::fast_terminate();
}
//Allow debug print
#ifndef FAST_IO_DISABLE_DEBUG_PRINT
//With debugging. We output to POSIX fd or Win32 Handle directly instead of C's stdout.
template<typename T,typename... Args>
inline constexpr void debug_print(T&& t,Args&& ...args)
{
constexpr bool device_error{fast_io::output_stream<std::remove_cvref_t<T>>||fast_io::status_output_stream<std::remove_cvref_t<T>>};
if constexpr(device_error)
{
constexpr bool type_error{::fast_io::print_freestanding_okay<T,Args...>};
if constexpr(type_error)
{
::fast_io::print_freestanding_decay<false>(::fast_io::io_ref(t),fast_io::io_print_forward<typename std::remove_cvref_t<T>::char_type>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for debug_print");
}
}
else
{
#if ((__STDC_HOSTED__==1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED==1) && !defined(_LIBCPP_FREESTANDING)) || defined(FAST_IO_ENABLE_HOSTED_FEATURES))
constexpr bool type_error{::fast_io::print_freestanding_okay<
#if defined(__AVR__)
::fast_io::c_io_observer
#else
::fast_io::native_io_observer
#endif
,T,Args...>};
if constexpr(type_error)
{
fast_io::details::debug_print_after_io_print_forward<false>(fast_io::io_print_forward<char>(fast_io::io_print_alias(t)),fast_io::io_print_forward<char>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for debug_print on native out");
}
#else
static_assert(device_error,"freestanding environment must provide IO device");
#endif
}
}
template<typename T,typename... Args>
inline constexpr void debug_println(T&& t,Args&& ...args)
{
constexpr bool device_error{::fast_io::output_stream<std::remove_cvref_t<T>>||::fast_io::status_output_stream<std::remove_cvref_t<T>>};
if constexpr(device_error)
{
constexpr bool type_error{::fast_io::print_freestanding_okay<T,Args...>};
if constexpr(type_error)
{
::fast_io::print_freestanding_decay<true>(::fast_io::io_ref(t),fast_io::io_print_forward<typename std::remove_cvref_t<T>::char_type>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for debug_println");
}
}
else
{
#if ((__STDC_HOSTED__==1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED==1) && !defined(_LIBCPP_FREESTANDING)) || defined(FAST_IO_ENABLE_HOSTED_FEATURES))
constexpr bool type_error{::fast_io::print_freestanding_okay<
#if defined(__AVR__)
::fast_io::c_io_observer
#else
::fast_io::native_io_observer
#endif
,T,Args...>};
if constexpr(type_error)
{
fast_io::details::debug_print_after_io_print_forward<true>(fast_io::io_print_forward<char>(fast_io::io_print_alias(t)),fast_io::io_print_forward<char>(fast_io::io_print_alias(args))...);
}
else
{
static_assert(type_error,"some types are not printable for debug_println on native out");
}
#else
static_assert(device_error,"freestanding environment must provide IO device");
#endif
}
}
template<typename... Args>
requires (sizeof...(Args)!=0)
inline constexpr void debug_perr(Args&&... args)
{
::fast_io::io::perr(::std::forward<Args>(args)...);
}
template<typename... Args>
requires (sizeof...(Args)!=0)
inline constexpr void debug_perrln(Args&&... args)
{
::fast_io::io::perrln(::std::forward<Args>(args)...);
}
#endif
template<bool report=false,typename input,typename... Args>
inline constexpr ::std::conditional_t<report,bool,void> scan(input&& in,Args&& ...args)
{
if constexpr(fast_io::input_stream<std::remove_cvref_t<input>>)
{
if constexpr(report)
return ::fast_io::scan_freestanding_decay(::fast_io::io_ref(in),fast_io::io_scan_forward<typename ::std::remove_cvref_t<input>::char_type>(::fast_io::io_scan_alias(args))...);
else
{
if(!::fast_io::scan_freestanding_decay(::fast_io::io_ref(in),::fast_io::io_scan_forward<typename ::std::remove_cvref_t<input>::char_type>(::fast_io::io_scan_alias(args))...))
::fast_io::throw_parse_code(::fast_io::parse_code::end_of_file);
}
}
else
{
#if ((__STDC_HOSTED__==1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED==1) && !defined(_LIBCPP_FREESTANDING)) || defined(FAST_IO_ENABLE_HOSTED_FEATURES)) && __has_include(<stdio.h>)
return ::fast_io::details::scan_after_io_scan_forward<report>(::fast_io::io_scan_forward<char>(::fast_io::io_scan_alias(in)),::fast_io::io_scan_forward<char>(::fast_io::io_scan_alias(args))...);
#else
static_assert(::fast_io::input_stream<std::remove_cvref_t<input>>,"freestanding environment must provide IO device");
#endif
}
}
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#endif
#endif
}
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#undef min
#undef max
//fast_io_concept.h allows you define your device and type without compilation time penalty
#if !defined(__cplusplus)
#error "You must be using a C++ compiler"
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
#pragma warning( disable : 4514 )
#pragma warning( disable : 4623 )
#pragma warning( disable : 4626 )
#pragma warning( disable : 4668 )
#pragma warning( disable : 4820 )
#pragma warning( disable : 5027 )
#endif
#if !defined(__cpp_concepts)
#error "fast_io requires at least a C++20 standard compiler."
#else
#include<version>
#include<cstddef>
#include<type_traits>
#include<concepts>
#include"fast_io_core_impl/freestanding/addressof.h"
#include"fast_io_core_impl/concepts/impl.h"
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning (pop)
#endif
+124
View File
@@ -0,0 +1,124 @@
#pragma once
//fast_io_core.h is required to be usable in freestanding environment with EVEN dynamic memory allocation and exceptions are disabled.
#if !defined(__cplusplus)
#error "You are not using a C++ compiler"
#endif
#if !defined(__cpp_concepts)
#error "fast_io requires at least C++20 standard compiler."
#else
#include"fast_io_concept.h"
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
#pragma warning( disable : 4711 )
#endif
#include<bit> //for std::endian, std::rotl and std::bit_cast etc
#include<limits>
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#endif
#include<cstdint>
#if __cpp_lib_three_way_comparison >= 201907L
#include<compare>
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
#pragma warning( disable : 4365 )
#pragma warning( disable : 4514 )
#pragma warning( disable : 4623 )
#pragma warning( disable : 4626 )
#pragma warning( disable : 4668 )
#pragma warning( disable : 4710 )
#pragma warning( disable : 4711 )
#pragma warning( disable : 4820 )
#pragma warning( disable : 5027 )
#pragma warning( disable : 5045 )
#endif
#include"fast_io_core_impl/empty.h"
#if defined(_MSC_VER) && !defined(__clang__)
#include "fast_io_core_impl/intrinsics/msvc/impl.h"
#endif
#include"fast_io_core_impl/freestanding/impl.h"
#include"fast_io_core_impl/terminate.h"
#include"fast_io_dsal/impl/freestanding.h"
#include"fast_io_core_impl/allocation/impl.h"
#include"fast_io_core_impl/error.h"
#include"fast_io_core_impl/asan_support.h"
//fast_io core
#include"fast_io_core_impl/utils.h"
#include"fast_io_core_impl/intrinsics.h"
#include"fast_io_core_impl/parse_code.h"
#include"fast_io_core_impl/ebcdic.h"
#include"fast_io_core_impl/literals/literal.h"
#include"fast_io_core_impl/char_category.h"
#include"fast_io_core_impl/overflow.h"
#if __cpp_lib_three_way_comparison >= 201907L
#include"fast_io_core_impl/compare.h"
#endif
#include"fast_io_core_impl/alias.h"
#include"fast_io_core_impl/pr_rsv.h"
#include"fast_io_core_impl/secure_clear_guard.h"
#include"fast_io_core_impl/local_new_array_ptr.h"
#include"fast_io_core_impl/dynamic_io_buffer.h"
#include"fast_io_core_impl/temporary_buffer.h"
// Although std::ranges is not freestanding, you can use the function by constructing a range_view_t, which relies on iterators not ranges
#include"fast_io_core_impl/range_view.h"
//#include"fast_io_core_impl/manip/impl.h"
#include"fast_io_core_impl/mode.h"
#include"fast_io_core_impl/perms.h"
#include"fast_io_core_impl/seek.h"
#include"fast_io_core_impl/igenerator.h"
#include"fast_io_core_impl/io_ref.h"
#include"fast_io_core_impl/print_freestanding.h"
#include"fast_io_core_impl/read_all.h"
#include"fast_io_core_impl/scan_freestanding.h"
// This should provide an option macro to disable any generation for table in freestanding environments.
#include"fast_io_core_impl/integers/integer.h"
#include"fast_io_core_impl/black_hole.h"
#include"fast_io_core_impl/buffer_view.h"
#include"fast_io_core_impl/transmit/impl.h"
#ifdef __cpp_lib_source_location
#include<source_location>
#include"fast_io_core_impl/source_location.h"
#endif
#include"fast_io_core_impl/simd/impl.h"
#include"fast_io_core_impl/simd_find.h"
#include"fast_io_core_impl/integers/sto/sto_contiguous.h"
#include"fast_io_core_impl/integers/chrono.h"
#include"fast_io_core_impl/iso/isos.h"
#include"fast_io_core_impl/enums/impl.h"
#ifndef FAST_IO_DISABLE_CODECVT
#include"fast_io_core_impl/codecvt/impl.h"
#endif
#include"fast_io_core_impl/io_deco_ref.h"
#include"fast_io_core_impl/timestamp_counter.h"
#include"fast_io_core_impl/dll_mode.h"
#include"fast_io_core_impl/socket/impl.h"
#include"fast_io_core_impl/to.h"
#include"fast_io_core_impl/concat/impl.h"
#include"fast_io_core_impl/http_header.h"
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#endif
#endif
@@ -0,0 +1,71 @@
#pragma once
namespace fast_io
{
namespace details
{
struct cannot_output_type
{
inline explicit constexpr cannot_output_type() noexcept = default;
};
}
template<typename T>
inline constexpr decltype(auto) io_print_alias(T&& t) noexcept
{
using no_cvref_t=std::remove_cvref_t<T>;
if constexpr(::std::is_function_v<no_cvref_t>)
{
return ::fast_io::details::cannot_output_type{};
}
else if constexpr(alias_printable<no_cvref_t>)
return print_alias_define(io_alias,::std::forward<T>(t));
else
return ::std::forward<T>(t);
}
template<std::integral char_type,typename T>
inline constexpr auto io_print_forward(T&& t) noexcept
{
using no_cvref_t=std::remove_cvref_t<T>;
if constexpr(::std::is_function_v<no_cvref_t>)
{
return ::fast_io::details::cannot_output_type{};
}
else if constexpr(status_io_print_forwardable<char_type,T>)
return status_io_print_forward(io_alias_type<char_type>,::std::forward<T>(t));
else if constexpr(std::is_trivially_copyable_v<no_cvref_t>&&sizeof(no_cvref_t)<=sizeof(std::size_t)*2)
return static_cast<no_cvref_t>(t);
else
return parameter<std::remove_reference_t<T> const&>{t};
}
template<std::integral char_type,typename T>
inline constexpr auto io_scan_forward(T t) noexcept
{
if constexpr(status_io_scan_forwardable<char_type,T>)
return status_io_scan_forward(io_alias_type<char_type>,t);
else
return t;
}
template<typename T>
inline constexpr auto io_scan_alias(T&& t) noexcept
{
using no_ref_t = std::remove_reference_t<T>;
if constexpr(::std::is_function_v<no_ref_t>)
{
return ::fast_io::details::cannot_output_type{};
}
else if constexpr(alias_scannable<no_ref_t>)
return scan_alias_define(io_alias,::std::forward<T>(t));
else if constexpr(manipulator<no_ref_t>)
return t;
else
return parameter<no_ref_t&>{t};
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,47 @@
#pragma once
enum class allocator_adapter_flags
{
none = 0,
record_size = 1,
secure_clear = 2
};
constexpr allocator_adapter_flags operator&(allocator_adapter_flags x, allocator_adapter_flags y) noexcept
{
using utype = typename ::std::underlying_type<allocator_adapter_flags>::type;
return static_cast<allocator_adapter_flags>(static_cast<utype>(x) & static_cast<utype>(y));
}
constexpr allocator_adapter_flags operator|(allocator_adapter_flags x, allocator_adapter_flags y) noexcept
{
using utype = typename ::std::underlying_type<allocator_adapter_flags>::type;
return static_cast<allocator_adapter_flags>(static_cast<utype>(x) | static_cast<utype>(y));
}
constexpr allocator_adapter_flags operator^(allocator_adapter_flags x, allocator_adapter_flags y) noexcept
{
using utype = typename ::std::underlying_type<allocator_adapter_flags>::type;
return static_cast<allocator_adapter_flags>(static_cast<utype>(x) ^ static_cast<utype>(y));
}
constexpr allocator_adapter_flags operator~(allocator_adapter_flags x) noexcept
{
using utype = typename ::std::underlying_type<allocator_adapter_flags>::type;
return static_cast<allocator_adapter_flags>(~static_cast<utype>(x));
}
inline constexpr allocator_adapter_flags &operator&=(allocator_adapter_flags &x, allocator_adapter_flags y) noexcept
{
return x = x & y;
}
inline constexpr allocator_adapter_flags &operator|=(allocator_adapter_flags &x, allocator_adapter_flags y) noexcept
{
return x = x | y;
}
inline constexpr allocator_adapter_flags &operator^=(allocator_adapter_flags &x, allocator_adapter_flags y) noexcept
{
return x = x ^ y;
}
@@ -0,0 +1,253 @@
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 6308)
#endif
#if __has_include(<malloc.h>)
#include <malloc.h>
#elif __has_include(<malloc_np.h>)
#include <malloc_np.h>
#endif
namespace fast_io
{
namespace details
{
#if (__has_include(<malloc.h>) || __has_include(<malloc_np.h>)) && !defined(__MSDOS__) && !defined(__LLVM_LIBC__)
inline ::std::size_t c_malloc_usable_size_impl(void *p) noexcept
{
#if defined(_WIN32) && !defined(__WINE__) && !defined(__CYGWIN__)
return ::fast_io::noexcept_call(_msize, p);
#else
return ::malloc_usable_size(p);
#endif
}
#endif
} // namespace details
class c_malloc_allocator
{
public:
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *allocate(::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
void *p =
#if defined(__has_builtin)
#if __has_builtin(__builtin_malloc)
__builtin_malloc(n)
#else
::std::malloc(n)
#endif
#else
::std::malloc(n)
#endif
;
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *reallocate(void *p, ::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
::std::size_t const to_allocate{n};
p =
#if defined(__has_builtin)
#if __has_builtin(__builtin_realloc)
__builtin_realloc
#else
::std::realloc
#endif
#else
::std::realloc
#endif
(p, to_allocate);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *allocate_zero(::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
void *p =
#if defined(__has_builtin)
#if __has_builtin(__builtin_calloc)
__builtin_calloc
#else
::std::calloc
#endif
#else
::std::calloc
#endif
(1, n);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if (__has_include(<malloc.h>) || __has_include(<malloc_np.h>)) && !defined(__MSDOS__) && !defined(__LLVM_LIBC__)
static inline allocation_least_result allocate_at_least(::std::size_t n) noexcept
{
auto p{::fast_io::c_malloc_allocator::allocate(n)};
return {p, ::fast_io::details::c_malloc_usable_size_impl(p)};
}
static inline allocation_least_result allocate_zero_at_least(::std::size_t n) noexcept
{
auto p{::fast_io::c_malloc_allocator::allocate_zero(n)};
return {p, ::fast_io::details::c_malloc_usable_size_impl(p)};
}
static inline allocation_least_result reallocate_at_least(void *oldp, ::std::size_t n) noexcept
{
auto p{::fast_io::c_malloc_allocator::reallocate(oldp, n)};
return {p, ::fast_io::details::c_malloc_usable_size_impl(p)};
}
#endif
#if defined(_WIN32) && !defined(__WINE__) && !defined(__CYGWIN__)
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *allocate_aligned(::std::size_t alignment, ::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
void *p;
if (alignment <= __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
p =
#if defined(__has_builtin)
#if __has_builtin(__builtin_malloc)
__builtin_malloc
#else
::std::malloc
#endif
#else
::std::malloc
#endif
(n);
}
else
{
p = ::fast_io::noexcept_call(_aligned_malloc, n, alignment);
}
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *reallocate_aligned(void *p, ::std::size_t alignment, ::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
if (alignment <= __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
p =
#if defined(__has_builtin)
#if __has_builtin(__builtin_realloc)
__builtin_realloc
#else
::std::realloc
#endif
#else
::std::realloc
#endif
(p, n);
}
else
{
p = ::fast_io::noexcept_call(_aligned_realloc, p, n, alignment);
}
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
static inline void deallocate_aligned(void *p, ::std::size_t alignment) noexcept
{
if (p == nullptr)
{
return;
}
if (alignment <= __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
#if defined(__has_builtin)
#if __has_builtin(__builtin_free)
__builtin_free
#else
::std::free
#endif
#else
::std::free
#endif
(p);
}
else
{
::fast_io::noexcept_call(_aligned_free, p);
}
}
#endif
static inline void deallocate(void *p) noexcept
{
if (p == nullptr)
{
return;
}
#if defined(__has_builtin)
#if __has_builtin(__builtin_free)
__builtin_free
#else
::std::free
#endif
#else
::std::free
#endif
(p);
}
};
} // namespace fast_io
#ifdef _MSC_VER
#pragma warning(pop)
#endif
@@ -0,0 +1,17 @@
#pragma once
namespace fast_io
{
template <typename Pointer>
struct basic_allocation_least_result
{
using pointer = Pointer;
using size_type = ::std::size_t;
pointer ptr;
size_type count;
};
using allocation_least_result = basic_allocation_least_result<void*>;
} // namespace fast_io
@@ -0,0 +1,14 @@
#pragma once
namespace fast_io
{
class custom_global_allocator;
#if defined(FAST_IO_DISABLE_CUSTOM_THREAD_LOCAL_ALLOCATOR)
using custom_thread_local_allocator = custom_global_allocator
#else
class custom_thread_local_allocator;
#endif
} // namespace fast_io
@@ -0,0 +1,289 @@
#pragma once
template <typename alloc>
concept has_allocate_impl = requires(::std::size_t n) {
{ alloc::allocate(n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_allocate_aligned_impl = requires(::std::size_t n) {
{ alloc::allocate_aligned(n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_allocate_zero_impl = requires(::std::size_t n) {
{ alloc::allocate_zero(n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_allocate_aligned_zero_impl = requires(::std::size_t n) {
{ alloc::allocate_aligned_zero(n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_reallocate_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate(p, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_reallocate_aligned_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_aligned(p, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_reallocate_zero_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_zero(p, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_reallocate_aligned_zero_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_aligned_zero(p, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_reallocate_n_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_n(p, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_reallocate_aligned_n_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_aligned_n(p, n, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_reallocate_zero_n_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_zero_n(p, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_reallocate_aligned_zero_n_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_aligned_zero_n(p, n, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_deallocate_impl = requires(void *p) {
{ alloc::deallocate(p) } -> ::std::same_as<void>;
};
template <typename alloc>
concept has_deallocate_aligned_impl = requires(void *p, ::std::size_t n) {
{ alloc::deallocate_aligned(p, n) } -> ::std::same_as<void>;
};
template <typename alloc>
concept has_deallocate_n_impl = requires(void *p, ::std::size_t n) {
{ alloc::deallocate_n(p, n) } -> ::std::same_as<void>;
};
template <typename alloc>
concept has_deallocate_aligned_n_impl = requires(void *p, ::std::size_t n) {
{ alloc::deallocate_aligned_n(p, n, n) } -> ::std::same_as<void>;
};
template <typename alloc>
concept has_allocate_at_least_impl = requires(::std::size_t n) {
{ alloc::allocate_at_least(n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_allocate_aligned_at_least_impl = requires(::std::size_t n) {
{ alloc::allocate_aligned_at_least(n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_allocate_zero_at_least_impl = requires(::std::size_t n) {
{ alloc::allocate_zero_at_least(n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_allocate_aligned_zero_at_least_impl = requires(::std::size_t n) {
{ alloc::allocate_aligned_zero_at_least(n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_reallocate_at_least_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_at_least(p, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_reallocate_aligned_at_least_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_aligned_at_least(p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_reallocate_zero_at_least_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_zero_at_least(p, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_reallocate_aligned_zero_at_least_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_aligned_zero_at_least(p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_reallocate_n_at_least_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_n_at_least(p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_reallocate_aligned_n_at_least_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_aligned_n_at_least(p, n, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_reallocate_zero_n_at_least_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_zero_n_at_least(p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_reallocate_aligned_zero_n_at_least_impl = requires(void *p, ::std::size_t n) {
{ alloc::reallocate_aligned_zero_n_at_least(p, n, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_non_empty_handle_type = requires {
typename alloc::handle_type;
requires !::std::is_empty_v<typename alloc::handle_type>;
};
template <typename alloc>
concept has_handle_allocate_impl = requires(typename alloc::handle_type handle, ::std::size_t n) {
{ alloc::handle_allocate(handle, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_allocate_aligned_impl = requires(typename alloc::handle_type handle, ::std::size_t n) {
{ alloc::handle_allocate_aligned(handle, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_allocate_zero_impl = requires(typename alloc::handle_type handle, ::std::size_t n) {
{ alloc::handle_allocate_zero(handle, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_allocate_aligned_zero_impl = requires(typename alloc::handle_type handle, ::std::size_t n) {
{ alloc::handle_allocate_aligned_zero(handle, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_reallocate_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate(handle, p, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_reallocate_aligned_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_aligned(handle, p, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_reallocate_zero_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_zero(handle, p, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_reallocate_aligned_zero_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_aligned_zero(handle, p, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_reallocate_n_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_n(handle, p, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_reallocate_aligned_n_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_aligned_n(handle, p, n, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_reallocate_zero_n_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_zero_n(handle, p, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_reallocate_aligned_zero_n_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_aligned_zero_n(handle, p, n, n, n) } -> ::std::same_as<void *>;
};
template <typename alloc>
concept has_handle_allocate_at_least_impl = requires(typename alloc::handle_type handle, ::std::size_t n) {
{ alloc::handle_allocate_at_least(handle, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_allocate_aligned_at_least_impl = requires(typename alloc::handle_type handle, ::std::size_t n) {
{ alloc::handle_allocate_aligned_at_least(handle, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_allocate_zero_at_least_impl = requires(typename alloc::handle_type handle, ::std::size_t n) {
{ alloc::handle_allocate_zero_at_least(handle, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_allocate_aligned_zero_at_least_impl = requires(typename alloc::handle_type handle, ::std::size_t n) {
{ alloc::handle_allocate_aligned_zero_at_least(handle, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_reallocate_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_at_least(handle, p, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_reallocate_aligned_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_aligned_at_least(handle, p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_reallocate_zero_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_zero_at_least(handle, p, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_reallocate_aligned_zero_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_aligned_zero_at_least(handle, p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_reallocate_n_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_n_at_least(handle, p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_reallocate_aligned_n_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_aligned_n_at_least(handle, p, n, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_reallocate_zero_n_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_zero_n_at_least(handle, p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_reallocate_aligned_zero_n_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_reallocate_aligned_zero_n_at_least(handle, p, n, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>;
};
template <typename alloc>
concept has_handle_deallocate_impl = requires(typename alloc::handle_type handle, void *p) {
{ alloc::handle_deallocate(handle, p) } -> ::std::same_as<void>;
};
template <typename alloc>
concept has_handle_deallocate_aligned_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_deallocate_aligned(handle, p, n) } -> ::std::same_as<void>;
};
template <typename alloc>
concept has_handle_deallocate_n_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_deallocate_n(handle, p, n) } -> ::std::same_as<void>;
};
template <typename alloc>
concept has_handle_deallocate_aligned_n_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) {
{ alloc::handle_deallocate_aligned_n(handle, p, n, n) } -> ::std::same_as<void>;
};
@@ -0,0 +1,76 @@
#pragma once
#include "common.h"
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(__WINE__)
#include "win32_heapalloc.h"
#include "nt_rtlheapalloc.h"
#if defined(_MSC_VER) && !defined(__clang__)
#include "msvc/impl.h"
#endif
#endif
#if ((__STDC_HOSTED__ == 1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED == 1) && \
!defined(_LIBCPP_FREESTANDING)) || \
defined(FAST_IO_ENABLE_HOSTED_FEATURES))
#include "c_malloc.h"
#if defined(_DEBUG) && defined(_MSC_VER)
#include "wincrt_malloc_dbg.h"
#endif
#endif
#if (defined(__linux__) && defined(__KERNEL__)) || defined(FAST_IO_USE_LINUX_KERNEL_ALLOCATOR)
#include "linux_kernel.h"
#endif
#if (defined(FAST_IO_ENABLE_MIMALLOC) || defined(FAST_IO_USE_MIMALLOC)) && (!defined(_MSC_VER) || defined(__clang__))
#include "mimalloc_driver.h"
#endif
#include "custom.h"
#include "adapters.h"
namespace fast_io
{
using native_global_allocator = generic_allocator_adapter<
#if defined(FAST_IO_USE_CUSTOM_GLOBAL_ALLOCATOR)
custom_global_allocator
#elif defined(FAST_IO_USE_MIMALLOC) && (!defined(_MSC_VER) || defined(__clang__))
mimalloc_allocator
#elif (defined(__linux__) && defined(__KERNEL__)) || defined(FAST_IO_USE_LINUX_KERNEL_ALLOCATOR)
linux_kmalloc_allocator
#elif ( \
(__STDC_HOSTED__ == 1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED == 1) && !defined(_LIBCPP_FREESTANDING)) || \
defined(FAST_IO_ENABLE_HOSTED_FEATURES))
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WINE__) && !defined(FAST_IO_USE_C_MALLOC)
#if defined(_DEBUG) && defined(_MSC_VER)
wincrt_malloc_dbg_allocator
#else
win32_heapalloc_allocator
#endif
#else
#if defined(_DEBUG) && defined(_MSC_VER)
wincrt_malloc_dbg_allocator
#else
c_malloc_allocator
#endif
#endif
#else
custom_global_allocator
#endif
>;
template <typename T>
using native_typed_global_allocator = typed_generic_allocator_adapter<native_global_allocator, T>;
using native_thread_local_allocator = generic_allocator_adapter<
#if defined(FAST_IO_USE_CUSTOM_THREAD_LOCAL_ALLOCATOR)
custom_thread_local_allocator
#else
native_global_allocator
#endif
>;
template <typename T>
using native_typed_thread_local_allocator = typed_generic_allocator_adapter<native_thread_local_allocator, T>;
} // namespace fast_io
@@ -0,0 +1,71 @@
#pragma once
namespace fast_io
{
extern void *linux_kernel_kmalloc(::std::size_t, int unsigned) noexcept __asm__("__kmalloc");
extern void *linux_kernel_krealloc(void const *, ::std::size_t, int unsigned) noexcept __asm__("krealloc");
extern void linux_kernel_kfree(void const *) noexcept __asm__("kfree");
inline constexpr int unsigned linux_kernel_gfp_kernel{0x400u | 0x800u | 0x40u | 0x80u};
inline constexpr int unsigned linux_kernel_gfp_kernel_zero{linux_kernel_gfp_kernel | 0x100u};
class linux_kmalloc_allocator
{
public:
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *allocate(::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
void *p = linux_kernel_kmalloc(n, linux_kernel_gfp_kernel);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
static inline void *reallocate(void *p, ::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
p = linux_kernel_krealloc(p, n, linux_kernel_gfp_kernel);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
static inline void *allocate_zero(::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
void *p = linux_kernel_kmalloc(n, linux_kernel_gfp_kernel_zero);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
static inline void deallocate(void *p) noexcept
{
if (p == nullptr)
{
return;
}
linux_kernel_kfree(p);
}
};
} // namespace fast_io
@@ -0,0 +1,159 @@
#pragma once
namespace fast_io
{
namespace mimalloc
{
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if __has_cpp_attribute(__gnu__::__cdecl__) && ((defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__))
[[__gnu__::__cdecl__]]
#endif
#if __has_cpp_attribute(__gnu__::__malloc__)
[[__gnu__::__malloc__]]
#endif
extern void *
#if !__has_cpp_attribute(__gnu__::__cdecl__) && defined(_MSC_VER)
__cdecl
#endif
mi_malloc(::std::size_t size) noexcept
#if (defined(__clang__) || defined(__GNUC__))
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__)) && \
((defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__))
#if !defined(__clang__)
__asm__("mi_malloc")
#else
__asm__("_mi_malloc")
#endif
#else
__asm__("mi_malloc")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if __has_cpp_attribute(__gnu__::__cdecl__) && ((defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__))
[[__gnu__::__cdecl__]]
#endif
extern void
#if !__has_cpp_attribute(__gnu__::__cdecl__) && defined(_MSC_VER)
__cdecl
#endif
mi_free(void *p) noexcept
#if (defined(__clang__) || defined(__GNUC__))
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__)) && \
((defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__))
#if !defined(__clang__)
__asm__("mi_free")
#else
__asm__("_mi_free")
#endif
#else
__asm__("mi_free")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if __has_cpp_attribute(__gnu__::__cdecl__) && ((defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__))
[[__gnu__::__cdecl__]]
#endif
extern void *
#if !__has_cpp_attribute(__gnu__::__cdecl__) && defined(_MSC_VER)
__cdecl
#endif
mi_calloc(::std::size_t count, ::std::size_t size) noexcept
#if (defined(__clang__) || defined(__GNUC__))
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__)) && \
((defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__))
#if !defined(__clang__)
__asm__("mi_calloc")
#else
__asm__("_mi_calloc")
#endif
#else
__asm__("mi_calloc")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if __has_cpp_attribute(__gnu__::__cdecl__) && ((defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__))
[[__gnu__::__cdecl__]]
#endif
extern void *
#if !__has_cpp_attribute(__gnu__::__cdecl__) && defined(_MSC_VER)
__cdecl
#endif
mi_realloc(void *p, ::std::size_t newsize) noexcept
#if (defined(__clang__) || defined(__GNUC__))
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__)) && \
((defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__))
#if !defined(__clang__)
__asm__("mi_realloc")
#else
__asm__("_mi_realloc")
#endif
#else
__asm__("mi_realloc")
#endif
#endif
;
} // namespace mimalloc
class mimalloc_allocator
{
public:
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *allocate(::std::size_t n) noexcept
{
void *p = ::fast_io::mimalloc::mi_malloc(n);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
static inline void *reallocate(void *p, ::std::size_t n) noexcept
{
p = ::fast_io::mimalloc::mi_realloc(p, n);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
static inline void *allocate_zero(::std::size_t n) noexcept
{
void *p = ::fast_io::mimalloc::mi_calloc(1, n);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
static inline void deallocate(void *p) noexcept
{
::fast_io::mimalloc::mi_free(p);
}
};
} // namespace fast_io
@@ -0,0 +1,9 @@
#pragma once
#if SIZE_MAX > UINT_LEAST32_MAX
#include "msvc_linker_64.h"
#elif defined(__x86__) || defined(_M_IX86) || defined(__i386__)
#include "msvc_linker_32_i686.h"
#else
#include "msvc_linker_32.h"
#endif
@@ -0,0 +1,15 @@
#pragma once
// clang-format off
#pragma comment(linker, "/alternatename:__imp_?HeapAlloc@win32@fast_io@@YAPAXPAXII@Z=__imp_HeapAlloc")
#pragma comment(linker, "/alternatename:__imp_?HeapFree@win32@fast_io@@YAHPAXI0@Z=__imp_HeapFree")
#pragma comment(linker, "/alternatename:__imp_?GetProcessHeap@win32@fast_io@@YAPAXXZ=__imp_GetProcessHeap")
#pragma comment(linker, "/alternatename:__imp_?HeapReAlloc@win32@fast_io@@YAPAXPAXI0I@Z=__imp_HeapReAlloc")
#pragma comment(linker, "/alternatename:__imp_?HeapSize@win32@fast_io@@YAIPAXIPBX@Z=__imp_HeapFree")
#pragma comment(linker, "/alternatename:__imp_?RtlAllocateHeap@nt@win32@fast_io@@YAPAXPAXII@Z=__imp_RtlAllocateHeap")
#pragma comment(linker, "/alternatename:__imp_?RtlFreeHeap@nt@win32@fast_io@@YAEPAXI0@Z=__imp_RtlFreeHeap")
#pragma comment(linker, "/alternatename:__imp_?RtlGetCurrentPeb@nt@win32@fast_io@@YAPAUpeb@123@XZ=__imp_RtlGetCurrentPeb")
#pragma comment(linker, "/alternatename:__imp_?RtlReAllocateHeap@nt@win32@fast_io@@YAPAXPAXI0I@Z=__imp_RtlReAllocateHeap")
#pragma comment(linker, "/alternatename:__imp_?RtlSizeHeap@nt@win32@fast_io@@YAIPAXI0@Z=__imp_RtlSizeHeap")
// clang-format on
@@ -0,0 +1,15 @@
#pragma once
// clang-format off
#pragma comment(linker, "/alternatename:__imp_?HeapAlloc@win32@fast_io@@YGPAXPAXII@Z=__imp__HeapAlloc@12")
#pragma comment(linker, "/alternatename:__imp_?HeapFree@win32@fast_io@@YGHPAXI0@Z=__imp__HeapFree@12")
#pragma comment(linker, "/alternatename:__imp_?GetProcessHeap@win32@fast_io@@YGPAXXZ=__imp__GetProcessHeap@0")
#pragma comment(linker, "/alternatename:__imp_?HeapReAlloc@win32@fast_io@@YGPAXPAXI0I@Z=__imp__HeapReAlloc@16")
#pragma comment(linker, "/alternatename:__imp_?HeapSize@win32@fast_io@@YGIPAXIPBX@Z=__imp__HeapSize@12")
#pragma comment(linker, "/alternatename:__imp_?RtlAllocateHeap@nt@win32@fast_io@@YGPAXPAXII@Z=__imp__RtlAllocateHeap@12")
#pragma comment(linker, "/alternatename:__imp_?RtlFreeHeap@nt@win32@fast_io@@YGEPAXI0@Z=__imp__RtlFreeHeap@12")
#pragma comment(linker, "/alternatename:__imp_?RtlGetCurrentPeb@nt@win32@fast_io@@YGPAUpeb@123@XZ=__imp__RtlGetCurrentPeb@0")
#pragma comment(linker, "/alternatename:__imp_?RtlReAllocateHeap@nt@win32@fast_io@@YGPAXPAXI0I@Z=__imp__RtlReAllocateHeap@16")
#pragma comment(linker, "/alternatename:__imp_?RtlSizeHeap@nt@win32@fast_io@@YGIPAXI0@Z=__imp__RtlSizeHeap@12")
// clang-format on
@@ -0,0 +1,15 @@
#pragma once
// clang-format off
#pragma comment(linker, "/alternatename:__imp_?HeapAlloc@win32@fast_io@@YAPEAXPEAXI_K@Z=__imp_HeapAlloc")
#pragma comment(linker, "/alternatename:__imp_?HeapFree@win32@fast_io@@YAHPEAXI0@Z=__imp_HeapFree")
#pragma comment(linker, "/alternatename:__imp_?GetProcessHeap@win32@fast_io@@YAPEAXXZ=__imp_GetProcessHeap")
#pragma comment(linker, "/alternatename:__imp_?HeapReAlloc@win32@fast_io@@YAPEAXPEAXI0_K@Z=__imp_HeapReAlloc")
#pragma comment(linker, "/alternatename:__imp_?HeapSize@win32@fast_io@@YA_KPEAXIPEBX@Z=__imp_HeapSize")
#pragma comment(linker, "/alternatename:__imp_?RtlAllocateHeap@nt@win32@fast_io@@YAPEAXPEAXI_K@Z=__imp_RtlAllocateHeap")
#pragma comment(linker, "/alternatename:__imp_?RtlFreeHeap@nt@win32@fast_io@@YAEPEAXI0@Z=__imp_RtlFreeHeap")
#pragma comment(linker, "/alternatename:__imp_?RtlGetCurrentPeb@nt@win32@fast_io@@YAPEAUpeb@123@XZ=__imp_RtlGetCurrentPeb")
#pragma comment(linker, "/alternatename:__imp_?RtlReAllocateHeap@nt@win32@fast_io@@YAPEAXPEAXI0_K@Z=__imp_RtlReAllocateHeap")
#pragma comment(linker, "/alternatename:__imp_?RtlSizeHeap@nt@win32@fast_io@@YA_KPEAXI0@Z=__imp_RtlSizeHeap")
// clang-format on
@@ -0,0 +1,354 @@
#pragma once
#if defined(_MSC_VER) && !defined(_KERNEL_MODE) && !defined(_WIN32_WINDOWS)
#pragma comment(lib, "ntdll.lib")
#endif
namespace fast_io
{
namespace win32::nt
{
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
extern void *
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
RtlAllocateHeap(void *, ::std::uint_least32_t, ::std::size_t) noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("RtlAllocateHeap@12")
#else
__asm__("_RtlAllocateHeap@12")
#endif
#else
__asm__("RtlAllocateHeap")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
extern char unsigned
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
RtlFreeHeap(void *, ::std::uint_least32_t, void *) noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("RtlFreeHeap@12")
#else
__asm__("_RtlFreeHeap@12")
#endif
#else
__asm__("RtlFreeHeap")
#endif
#endif
;
struct peb_ldr_data;
struct rtl_user_process_parameters;
using pps_post_process_init_routine = void(
#if defined(_MSC_VER) && (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
__stdcall
#elif (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
__attribute__((__stdcall__))
#endif
*)(void) noexcept;
struct peb
{
char unsigned InheritedAddressSpace;
char unsigned ReadImageFileExecOptions;
char unsigned BeingDebugged;
char unsigned SpareBool;
void *Mutant;
void *ImageBaseAddress;
peb_ldr_data *Ldr;
rtl_user_process_parameters *ProcessParameters; // PRTL_USER_PROCESS_PARAMETERS
void *SubSystemData;
void *ProcessHeap;
void *FastPebLock;
void *FastPebLockRoutine;
void *FastPebUnlockRoutine;
::std::uint_least32_t Reserved6;
void *Reserved7;
::std::uint_least32_t Reserved8;
::std::uint_least32_t AtlThunkSListPtr32;
void *Reserved9[45];
char unsigned Reserved10[96];
pps_post_process_init_routine PostProcessInitRoutine;
char unsigned Reserved11[128];
void *Reserved12[1];
::std::uint_least32_t SessionId;
};
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
#if __has_cpp_attribute(__gnu__::__const__)
[[__gnu__::__const__]]
#endif
extern peb *
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
RtlGetCurrentPeb() noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("RtlGetCurrentPeb@0")
#else
__asm__("_RtlGetCurrentPeb@0")
#endif
#else
__asm__("RtlGetCurrentPeb")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
extern void *
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
RtlReAllocateHeap(void *, ::std::uint_least32_t, void *, ::std::size_t) noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("RtlReAllocateHeap@16")
#else
__asm__("_RtlReAllocateHeap@16")
#endif
#else
__asm__("RtlReAllocateHeap")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
extern ::std::size_t
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
RtlSizeHeap(void *, ::std::uint_least32_t, void *) noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("RtlSizeHeap@12")
#else
__asm__("_RtlSizeHeap@12")
#endif
#else
__asm__("RtlSizeHeap")
#endif
#endif
;
#if __has_cpp_attribute(__gnu__::__const__)
[[__gnu__::__const__]]
#endif
inline peb *nt_get_current_peb() noexcept
{
#if (defined(__clang__) || defined(__GNUC__)) && (defined(__i386__) || defined(__x86_64__))
if constexpr (sizeof(::std::size_t) == sizeof(::std::uint_least64_t))
{
peb *ppeb;
__asm__("{movq\t%%gs:0x60, %0|mov\t%0, %%gs:[0x60]}" : "=r"(ppeb));
return ppeb;
}
else if constexpr (sizeof(::std::size_t) == sizeof(::std::uint_least32_t))
{
peb *ppeb;
__asm__("{movl\t%%fs:0x30, %0|mov\t%0, %%fs:[0x30]}" : "=r"(ppeb));
return ppeb;
}
else
{
return ::fast_io::win32::nt::RtlGetCurrentPeb();
}
#elif defined(_MSC_VER) && !defined(__clang__) && (defined(_M_IX86) || defined(_M_AMD64))
#if defined(_M_AMD64)
return reinterpret_cast<peb *>(::fast_io::intrinsics::msvc::x86::__readgsqword(0x60));
#else
return reinterpret_cast<peb *>(::fast_io::intrinsics::msvc::x86::__readfsdword(0x30));
#endif
#else
return ::fast_io::win32::nt::RtlGetCurrentPeb();
#endif
}
#if __has_cpp_attribute(__gnu__::__const__)
[[__gnu__::__const__]]
#endif
inline void *rtl_get_process_heap() noexcept
{
return ::fast_io::win32::nt::nt_get_current_peb()->ProcessHeap;
}
} // namespace win32::nt
namespace details
{
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
inline void *nt_rtlallocate_heap_handle_common_impl(void *heaphandle, ::std::size_t n, ::std::uint_least32_t flag) noexcept
{
if (n == 0)
{
n = 1;
}
auto p{::fast_io::win32::nt::RtlAllocateHeap(heaphandle, flag, n)};
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
inline void *nt_rtlreallocate_heap_handle_common_impl(void *heaphandle, void *addr, ::std::size_t n, ::std::uint_least32_t flag) noexcept
{
if (n == 0)
{
n = 1;
}
if (addr == nullptr)
#if __has_cpp_attribute(unlikely)
[[unlikely]]
#endif
{
return ::fast_io::details::nt_rtlallocate_heap_handle_common_impl(heaphandle, n, flag);
}
auto p{::fast_io::win32::nt::RtlReAllocateHeap(heaphandle, flag, addr, n)};
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
inline void *nt_rtlallocate_heap_common_impl(::std::size_t n, ::std::uint_least32_t flag) noexcept
{
return ::fast_io::details::nt_rtlallocate_heap_handle_common_impl(::fast_io::win32::nt::rtl_get_process_heap(), n, flag);
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
inline void *nt_rtlreallocate_heap_common_impl(void *addr, ::std::size_t n, ::std::uint_least32_t flag) noexcept
{
return ::fast_io::details::nt_rtlreallocate_heap_handle_common_impl(::fast_io::win32::nt::rtl_get_process_heap(), addr, n, flag);
}
inline ::fast_io::allocation_least_result nt_rtlallocate_heap_least_common_impl(::std::size_t n, ::std::uint_least32_t flag) noexcept
{
auto processheap{::fast_io::win32::nt::rtl_get_process_heap()};
auto ptr{::fast_io::details::nt_rtlallocate_heap_handle_common_impl(processheap, n, flag)};
return {ptr, ::fast_io::win32::nt::RtlSizeHeap(processheap, 0, ptr)};
}
inline ::fast_io::allocation_least_result nt_rtlreallocate_heap_least_common_impl(void *addr, ::std::size_t n, ::std::uint_least32_t flag) noexcept
{
auto processheap{::fast_io::win32::nt::rtl_get_process_heap()};
auto ptr{::fast_io::details::nt_rtlreallocate_heap_handle_common_impl(processheap, addr, n, flag)};
return {ptr, ::fast_io::win32::nt::RtlSizeHeap(processheap, 0, ptr)};
}
} // namespace details
class nt_rtlallocateheap_allocator
{
public:
#if __has_cpp_attribute(__gnu__::__malloc__)
[[__gnu__::__malloc__]]
#endif
static inline void *allocate(::std::size_t n) noexcept
{
return ::fast_io::details::nt_rtlallocate_heap_common_impl(n, 0u);
}
#if __has_cpp_attribute(__gnu__::__malloc__)
[[__gnu__::__malloc__]]
#endif
static inline void *allocate_zero(::std::size_t n) noexcept
{
return ::fast_io::details::nt_rtlallocate_heap_common_impl(n, 0x00000008u);
}
static inline void *reallocate(void *addr, ::std::size_t n) noexcept
{
return ::fast_io::details::nt_rtlreallocate_heap_common_impl(addr, n, 0u);
}
static inline void *reallocate_zero(void *addr, ::std::size_t n) noexcept
{
return ::fast_io::details::nt_rtlreallocate_heap_common_impl(addr, n, 0x00000008u);
}
static inline void deallocate(void *addr) noexcept
{
if (addr == nullptr)
{
return;
}
::fast_io::win32::nt::RtlFreeHeap(::fast_io::win32::nt::rtl_get_process_heap(), 0u, addr);
}
#if 0
static inline ::fast_io::allocation_least_result allocate_at_least(::std::size_t n) noexcept
{
return ::fast_io::details::nt_rtlallocate_heap_least_common_impl(n, 0u);
}
static inline ::fast_io::allocation_least_result allocate_zero_at_least(::std::size_t n) noexcept
{
return ::fast_io::details::nt_rtlallocate_heap_least_common_impl(n, 0x00000008u);
}
static inline ::fast_io::allocation_least_result reallocate_at_least(void *addr, ::std::size_t n) noexcept
{
return ::fast_io::details::nt_rtlreallocate_heap_least_common_impl(addr, n, 0u);
}
static inline ::fast_io::allocation_least_result reallocate_zero_at_least(void *addr, ::std::size_t n) noexcept
{
return ::fast_io::details::nt_rtlreallocate_heap_least_common_impl(addr, n, 0x00000008u);
}
#endif
};
} // namespace fast_io
@@ -0,0 +1,275 @@
#pragma once
namespace fast_io
{
namespace win32
{
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
#if __has_cpp_attribute(__gnu__::__malloc__)
[[__gnu__::__malloc__]]
#endif
extern void *
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
HeapAlloc(void *, ::std::uint_least32_t, ::std::size_t) noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("HeapAlloc@12")
#else
__asm__("_HeapAlloc@12")
#endif
#else
__asm__("HeapAlloc")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
extern int
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
HeapFree(void *, ::std::uint_least32_t, void *) noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("HeapFree@12")
#else
__asm__("_HeapFree@12")
#endif
#else
__asm__("HeapFree")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
#if __has_cpp_attribute(__gnu__::__const__)
[[__gnu__::__const__]]
#endif
extern void *
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
GetProcessHeap() noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("GetProcessHeap@0")
#else
__asm__("_GetProcessHeap@0")
#endif
#else
__asm__("GetProcessHeap")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
extern void *
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
HeapReAlloc(void *, ::std::uint_least32_t, void *, ::std::size_t) noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("HeapReAlloc@16")
#else
__asm__("_HeapReAlloc@16")
#endif
#else
__asm__("HeapReAlloc")
#endif
#endif
;
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(dllimport)
#elif (__has_cpp_attribute(__gnu__::__dllimport__) && !defined(__WINE__))
[[__gnu__::__dllimport__]]
#endif
#if (__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__))
[[__gnu__::__stdcall__]]
#endif
extern ::std::size_t
#if (!__has_cpp_attribute(__gnu__::__stdcall__) && !defined(__WINE__)) && defined(_MSC_VER)
__stdcall
#endif
HeapSize(void *, ::std::uint_least32_t, void const *) noexcept
#if defined(__clang__) || defined(__GNUC__)
#if SIZE_MAX <= UINT_LEAST32_MAX && (defined(__x86__) || defined(_M_IX86) || defined(__i386__))
#if !defined(__clang__)
__asm__("HeapSize@12")
#else
__asm__("_HeapSize@12")
#endif
#else
__asm__("HeapSize")
#endif
#endif
;
} // namespace win32
namespace details
{
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
inline void *win32_heapalloc_handle_common_impl(void *heaphandle, ::std::size_t n, ::std::uint_least32_t flag) noexcept
{
if (n == 0)
{
n = 1;
}
auto p{::fast_io::win32::HeapAlloc(heaphandle, flag, n)};
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
inline void *win32_heaprealloc_handle_common_impl(void *heaphandle, void *addr, ::std::size_t n, ::std::uint_least32_t flag) noexcept
{
if (n == 0)
{
n = 1;
}
if (addr == nullptr)
#if __has_cpp_attribute(unlikely)
[[unlikely]]
#endif
{
return win32_heapalloc_handle_common_impl(heaphandle, n, flag);
}
auto p{::fast_io::win32::HeapReAlloc(heaphandle, flag, addr, n)};
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
inline void *win32_heapalloc_common_impl(::std::size_t n, ::std::uint_least32_t flag) noexcept
{
return ::fast_io::details::win32_heapalloc_handle_common_impl(::fast_io::win32::GetProcessHeap(), n, flag);
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
inline void *win32_heaprealloc_common_impl(void *addr, ::std::size_t n, ::std::uint_least32_t flag) noexcept
{
return ::fast_io::details::win32_heaprealloc_handle_common_impl(::fast_io::win32::GetProcessHeap(), addr, n, flag);
}
inline ::fast_io::allocation_least_result win32_heapalloc_least_common_impl(::std::size_t n, ::std::uint_least32_t flag) noexcept
{
auto processheap{::fast_io::win32::GetProcessHeap()};
auto ptr{::fast_io::details::win32_heapalloc_handle_common_impl(processheap, n, flag)};
return {ptr, ::fast_io::win32::HeapSize(processheap, 0, ptr)};
}
inline ::fast_io::allocation_least_result win32_heaprealloc_least_common_impl(void *addr, ::std::size_t n, ::std::uint_least32_t flag) noexcept
{
auto processheap{::fast_io::win32::GetProcessHeap()};
auto ptr{::fast_io::details::win32_heaprealloc_handle_common_impl(processheap, addr, n, flag)};
return {ptr, ::fast_io::win32::HeapSize(processheap, 0, ptr)};
}
} // namespace details
class win32_heapalloc_allocator
{
public:
#if __has_cpp_attribute(__gnu__::__malloc__)
[[__gnu__::__malloc__]]
#endif
static inline void *allocate(::std::size_t n) noexcept
{
return ::fast_io::details::win32_heapalloc_common_impl(n, 0u);
}
#if __has_cpp_attribute(__gnu__::__malloc__)
[[__gnu__::__malloc__]]
#endif
static inline void *allocate_zero(::std::size_t n) noexcept
{
return ::fast_io::details::win32_heapalloc_common_impl(n, 0x00000008u);
}
static inline void *reallocate(void *addr, ::std::size_t n) noexcept
{
return ::fast_io::details::win32_heaprealloc_common_impl(addr, n, 0u);
}
static inline void *reallocate_zero(void *addr, ::std::size_t n) noexcept
{
return ::fast_io::details::win32_heaprealloc_common_impl(addr, n, 0x00000008u);
}
static inline void deallocate(void *addr) noexcept
{
if (addr == nullptr)
{
return;
}
::fast_io::win32::HeapFree(::fast_io::win32::GetProcessHeap(), 0u, addr);
}
#if 0
static inline ::fast_io::allocation_least_result allocate_at_least(::std::size_t n) noexcept
{
return ::fast_io::details::win32_heapalloc_least_common_impl(n, 0u);
}
static inline ::fast_io::allocation_least_result allocate_zero_at_least(::std::size_t n) noexcept
{
return ::fast_io::details::win32_heapalloc_least_common_impl(n, 0x00000008u);
}
static inline ::fast_io::allocation_least_result reallocate_at_least(void *addr, ::std::size_t n) noexcept
{
return ::fast_io::details::win32_heaprealloc_least_common_impl(addr, n, 0u);
}
static inline ::fast_io::allocation_least_result reallocate_zero_at_least(void *addr, ::std::size_t n) noexcept
{
return ::fast_io::details::win32_heaprealloc_least_common_impl(addr, n, 0x00000008u);
}
#endif
};
} // namespace fast_io
@@ -0,0 +1,96 @@
#pragma once
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable : 6308)
#endif
#include <crtdbg.h>
namespace fast_io
{
class wincrt_malloc_dbg_allocator
{
public:
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *allocate(::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
void *p = ::fast_io::noexcept_call(_malloc_dbg, n, 1, __FILE__, __LINE__);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *reallocate(void *p, ::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
p = ::fast_io::noexcept_call(_realloc_dbg, p, n, 1, __FILE__, __LINE__);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
#if __has_cpp_attribute(__gnu__::__returns_nonnull__)
[[__gnu__::__returns_nonnull__]]
#endif
static inline void *allocate_zero(::std::size_t n) noexcept
{
if (n == 0)
{
n = 1;
}
void *p = ::fast_io::noexcept_call(_calloc_dbg, 1, n, 1, __FILE__, __LINE__);
if (p == nullptr)
{
::fast_io::fast_terminate();
}
return p;
}
static inline void deallocate(void *p) noexcept
{
if (p == nullptr)
{
return;
}
::fast_io::noexcept_call(_free_dbg, p, 1);
}
#if 0
static inline allocation_least_result allocate_at_least(::std::size_t n) noexcept
{
auto p{::fast_io::wincrt_malloc_dbg_allocator::allocate(n)};
return {p, ::fast_io::noexcept_call(_msize_dbg, p, 1)};
}
static inline allocation_least_result allocate_zero_at_least(::std::size_t n) noexcept
{
auto p{::fast_io::wincrt_malloc_dbg_allocator::allocate_zero(n)};
return {p, ::fast_io::noexcept_call(_msize_dbg, p, 1)};
}
static inline allocation_least_result reallocate_at_least(void *oldp, ::std::size_t n) noexcept
{
auto p{::fast_io::wincrt_malloc_dbg_allocator::reallocate(oldp, n)};
return {p, ::fast_io::noexcept_call(_msize_dbg, p, 1)};
}
#endif
};
} // namespace fast_io
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#endif
@@ -0,0 +1,28 @@
#pragma once
namespace fast_io::details
{
enum class asan_state
{
none,
activate,
current=
#if (defined(_GLIBCXX_DEBUG) || defined(_DEBUG) || _ITERATOR_DEBUG_LEVEL>=2 || _LIBCPP_DEBUG >= 2 || defined(FAST_IO_SANITIZE_IO_BUFFER))
#if defined(__SANITIZE_ADDRESS__)
activate
#elif defined(__has_feature)
#if __has_feature(address_sanitizer)
activate
#else
none
#endif
#else
none
#endif
#else
none
#endif
};
}
@@ -0,0 +1,28 @@
#pragma once
namespace fast_io
{
//black_hole is a helper class which helps you remove device requirement for iobuf or iotransform.
//sha256 for example. You do not need a real device. You want to send all your bits to black hole
template<std::integral ch_type>
struct basic_black_hole
{
public:
using char_type = ch_type;
};
template<std::integral ch_type,::std::contiguous_iterator Iter>
inline constexpr void write(basic_black_hole<ch_type>,Iter,Iter){}
template<std::integral ch_type,::std::contiguous_iterator Iter>
inline constexpr Iter read(basic_black_hole<ch_type>,Iter b,Iter){return b;}
template<std::integral ch_type>
inline constexpr basic_black_hole<ch_type> io_value_handle(basic_black_hole<ch_type> h) noexcept
{
return h;
}
}
@@ -0,0 +1,195 @@
#pragma once
namespace fast_io
{
template<std::integral ch_type>
struct basic_ibuffer_view
{
using char_type = ch_type;
char_type const *begin_ptr{};
char_type const *curr_ptr{};
char_type const *end_ptr{};
constexpr basic_ibuffer_view() noexcept = default;
template<::std::contiguous_iterator Iter>
requires std::same_as<std::remove_cvref_t<::std::iter_value_t<Iter>>,char_type>
constexpr basic_ibuffer_view(Iter first,Iter last) noexcept:begin_ptr{::std::to_address(first)},curr_ptr{begin_ptr},end_ptr{curr_ptr+(last-first)}{}
template<std::ranges::contiguous_range rg>
requires (std::same_as<::std::ranges::range_value_t<rg>,char_type>&&!::std::is_array_v<std::remove_cvref_t<rg>>)
explicit constexpr basic_ibuffer_view(rg& r) noexcept : basic_ibuffer_view(::std::ranges::cbegin(r),::std::ranges::cend(r)){}
constexpr void clear() noexcept
{
curr_ptr=begin_ptr;
}
};
template<std::integral ch_type,::std::contiguous_iterator Iter>
requires std::same_as<::std::iter_value_t<Iter>,ch_type>
[[nodiscard]] inline constexpr Iter read(basic_ibuffer_view<ch_type>& view,Iter first,Iter last) noexcept
{
auto diff{last-first};
auto view_diff{view.end_ptr-view.curr_ptr};
if(view_diff<diff)
diff=view_diff;
auto it{::fast_io::details::non_overlapped_copy_n(view.curr_ptr,static_cast<std::size_t>(view_diff),first)};
view.curr_ptr+=diff;
return it;
}
template<std::integral ch_type>
[[nodiscard]] constexpr ch_type const* ibuffer_begin(basic_ibuffer_view<ch_type>& view) noexcept
{
return view.begin_ptr;
}
template<std::integral ch_type>
[[nodiscard]] constexpr ch_type const* ibuffer_curr(basic_ibuffer_view<ch_type>& view) noexcept
{
return view.curr_ptr;
}
template<std::integral ch_type>
[[nodiscard]] constexpr ch_type const* ibuffer_end(basic_ibuffer_view<ch_type>& view) noexcept
{
return view.end_ptr;
}
template<std::integral ch_type>
constexpr void ibuffer_set_curr(basic_ibuffer_view<ch_type>& view,ch_type const* ptr) noexcept
{
view.curr_ptr=ptr;
}
template<std::integral ch_type>
[[nodiscard]] constexpr bool ibuffer_underflow(basic_ibuffer_view<ch_type>&) noexcept
{
return false;
}
template<std::integral ch_type>
inline constexpr bool ibuffer_underflow_never(basic_ibuffer_view<ch_type>&) noexcept
{
return true;
}
template<std::integral ch_type>
struct basic_obuffer_view
{
using char_type = ch_type;
char_type *begin_ptr{},*curr_ptr{},*end_ptr{};
constexpr basic_obuffer_view() noexcept = default;
template<::std::contiguous_iterator Iter>
requires std::same_as<::std::iter_value_t<Iter>,char_type>
constexpr basic_obuffer_view(Iter first,Iter last) noexcept:begin_ptr{::std::to_address(first)},
curr_ptr{begin_ptr},
end_ptr{::std::to_address(last)}{}
template<std::ranges::contiguous_range rg>
requires (std::same_as<::std::ranges::range_value_t<rg>,char_type>&&!::std::is_array_v<std::remove_cvref_t<rg>>)
explicit constexpr basic_obuffer_view(rg& r) noexcept : basic_obuffer_view(::std::ranges::begin(r),::std::ranges::end(r)){}
constexpr void clear() noexcept
{
curr_ptr=begin_ptr;
}
constexpr char_type const* cbegin() const noexcept
{
return begin_ptr;
}
constexpr char_type const* cend() const noexcept
{
return curr_ptr;
}
constexpr char_type const* begin() const noexcept
{
return begin_ptr;
}
constexpr char_type const* end() const noexcept
{
return curr_ptr;
}
constexpr char_type* begin() noexcept
{
return begin_ptr;
}
constexpr char_type* end() noexcept
{
return curr_ptr;
}
constexpr char_type const* data() const noexcept
{
return begin_ptr;
}
constexpr char_type* data() noexcept
{
return begin_ptr;
}
constexpr std::size_t size() const noexcept
{
return static_cast<std::size_t>(curr_ptr-begin_ptr);
}
constexpr std::size_t capacity() const noexcept
{
return static_cast<std::size_t>(end_ptr-begin_ptr);
}
};
template<std::integral ch_type,::std::contiguous_iterator Iter>
requires std::same_as<::std::iter_value_t<Iter>,ch_type>
inline constexpr void write(basic_obuffer_view<ch_type>& view,Iter first,Iter last) noexcept
{
auto diff{last-first};
auto view_diff{view.end_ptr-view.curr_ptr};
if(view_diff<diff)
fast_terminate();
view.curr_ptr=::fast_io::details::non_overlapped_copy_n(first,static_cast<std::size_t>(diff),view.curr_ptr);
}
template<std::integral ch_type>
[[nodiscard]] constexpr ch_type* obuffer_begin(basic_obuffer_view<ch_type>& view) noexcept
{
return view.begin_ptr;
}
template<std::integral ch_type>
[[nodiscard]] constexpr ch_type* obuffer_curr(basic_obuffer_view<ch_type>& view) noexcept
{
return view.curr_ptr;
}
template<std::integral ch_type>
[[nodiscard]] constexpr ch_type* obuffer_end(basic_obuffer_view<ch_type>& view) noexcept
{
return view.end_ptr;
}
template<std::integral ch_type>
constexpr void obuffer_set_curr(basic_obuffer_view<ch_type>& view,ch_type* ptr) noexcept
{
view.curr_ptr=ptr;
}
template<std::integral ch_type>
constexpr void obuffer_overflow(basic_obuffer_view<ch_type>&,ch_type) noexcept
{
fast_terminate();
}
template<std::integral ch_type>
inline constexpr bool obuffer_overflow_never(basic_obuffer_view<ch_type>&) noexcept
{
return true;
}
using ibuffer_view = basic_ibuffer_view<char>;
using wibuffer_view = basic_ibuffer_view<wchar_t>;
using u8ibuffer_view = basic_ibuffer_view<char8_t>;
using u16ibuffer_view = basic_ibuffer_view<char16_t>;
using u32ibuffer_view = basic_ibuffer_view<char32_t>;
using obuffer_view = basic_obuffer_view<char>;
using wobuffer_view = basic_obuffer_view<wchar_t>;
using u8obuffer_view = basic_obuffer_view<char8_t>;
using u16obuffer_view = basic_obuffer_view<char16_t>;
using u32obuffer_view = basic_obuffer_view<char32_t>;
}
@@ -0,0 +1,500 @@
#pragma once
namespace fast_io::char_category
{
template<std::integral char_type>
inline constexpr bool is_c_alnum(char_type ch) noexcept
{
if constexpr(std::same_as<char,char_type>)
switch(ch){case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':case 'G':case 'H':case 'I':case 'J':case 'K':case 'L':case 'M':case 'N':case 'O':case 'P':case 'Q':case 'R':case 'S':case 'T':case 'U':case 'V':case 'W':case 'X':case 'Y':case 'Z':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':case 'q':case 'r':case 's':case 't':case 'u':case 'v':case 'w':case 'x':case 'y':case 'z':return true;default:return false;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'0':case L'1':case L'2':case L'3':case L'4':case L'5':case L'6':case L'7':case L'8':case L'9':case L'A':case L'B':case L'C':case L'D':case L'E':case L'F':case L'G':case L'H':case L'I':case L'J':case L'K':case L'L':case L'M':case L'N':case L'O':case L'P':case L'Q':case L'R':case L'S':case L'T':case L'U':case L'V':case L'W':case L'X':case L'Y':case L'Z':case L'a':case L'b':case L'c':case L'd':case L'e':case L'f':case L'g':case L'h':case L'i':case L'j':case L'k':case L'l':case L'm':case L'n':case L'o':case L'p':case L'q':case L'r':case L's':case L't':case L'u':case L'v':case L'w':case L'x':case L'y':case L'z':return true;default:return false;}
else
switch(ch){case u8'0':case u8'1':case u8'2':case u8'3':case u8'4':case u8'5':case u8'6':case u8'7':case u8'8':case u8'9':case u8'A':case u8'B':case u8'C':case u8'D':case u8'E':case u8'F':case u8'G':case u8'H':case u8'I':case u8'J':case u8'K':case u8'L':case u8'M':case u8'N':case u8'O':case u8'P':case u8'Q':case u8'R':case u8'S':case u8'T':case u8'U':case u8'V':case u8'W':case u8'X':case u8'Y':case u8'Z':case u8'a':case u8'b':case u8'c':case u8'd':case u8'e':case u8'f':case u8'g':case u8'h':case u8'i':case u8'j':case u8'k':case u8'l':case u8'm':case u8'n':case u8'o':case u8'p':case u8'q':case u8'r':case u8's':case u8't':case u8'u':case u8'v':case u8'w':case u8'x':case u8'y':case u8'z':return true;default:return false;}
}
template<std::integral char_type>
inline constexpr bool is_c_alpha(char_type ch) noexcept
{
if constexpr(std::same_as<char,char_type>)
switch(ch){case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':case 'G':case 'H':case 'I':case 'J':case 'K':case 'L':case 'M':case 'N':case 'O':case 'P':case 'Q':case 'R':case 'S':case 'T':case 'U':case 'V':case 'W':case 'X':case 'Y':case 'Z':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':case 'q':case 'r':case 's':case 't':case 'u':case 'v':case 'w':case 'x':case 'y':case 'z':return true;default:return false;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'A':case L'B':case L'C':case L'D':case L'E':case L'F':case L'G':case L'H':case L'I':case L'J':case L'K':case L'L':case L'M':case L'N':case L'O':case L'P':case L'Q':case L'R':case L'S':case L'T':case L'U':case L'V':case L'W':case L'X':case L'Y':case L'Z':case L'a':case L'b':case L'c':case L'd':case L'e':case L'f':case L'g':case L'h':case L'i':case L'j':case L'k':case L'l':case L'm':case L'n':case L'o':case L'p':case L'q':case L'r':case L's':case L't':case L'u':case L'v':case L'w':case L'x':case L'y':case L'z':return true;default:return false;}
else
switch(ch){case u8'A':case u8'B':case u8'C':case u8'D':case u8'E':case u8'F':case u8'G':case u8'H':case u8'I':case u8'J':case u8'K':case u8'L':case u8'M':case u8'N':case u8'O':case u8'P':case u8'Q':case u8'R':case u8'S':case u8'T':case u8'U':case u8'V':case u8'W':case u8'X':case u8'Y':case u8'Z':case u8'a':case u8'b':case u8'c':case u8'd':case u8'e':case u8'f':case u8'g':case u8'h':case u8'i':case u8'j':case u8'k':case u8'l':case u8'm':case u8'n':case u8'o':case u8'p':case u8'q':case u8'r':case u8's':case u8't':case u8'u':case u8'v':case u8'w':case u8'x':case u8'y':case u8'z':return true;default:return false;}
}
template<std::integral char_type>
inline constexpr bool is_c_lower(char_type ch) noexcept
{
if constexpr(std::same_as<char,char_type>)
switch(ch){case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':case 'q':case 'r':case 's':case 't':case 'u':case 'v':case 'w':case 'x':case 'y':case 'z':return true;default:return false;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'a':case L'b':case L'c':case L'd':case L'e':case L'f':case L'g':case L'h':case L'i':case L'j':case L'k':case L'l':case L'm':case L'n':case L'o':case L'p':case L'q':case L'r':case L's':case L't':case L'u':case L'v':case L'w':case L'x':case L'y':case L'z':return true;default:return false;}
else
switch(ch){case u8'a':case u8'b':case u8'c':case u8'd':case u8'e':case u8'f':case u8'g':case u8'h':case u8'i':case u8'j':case u8'k':case u8'l':case u8'm':case u8'n':case u8'o':case u8'p':case u8'q':case u8'r':case u8's':case u8't':case u8'u':case u8'v':case u8'w':case u8'x':case u8'y':case u8'z':return true;default:return false;}
}
template<std::integral char_type>
inline constexpr bool is_c_upper(char_type ch) noexcept
{
if constexpr(std::same_as<char,char_type>)
switch(ch){case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':case 'G':case 'H':case 'I':case 'J':case 'K':case 'L':case 'M':case 'N':case 'O':case 'P':case 'Q':case 'R':case 'S':case 'T':case 'U':case 'V':case 'W':case 'X':case 'Y':case 'Z':return true;default:return false;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'A':case L'B':case L'C':case L'D':case L'E':case L'F':case L'G':case L'H':case L'I':case L'J':case L'K':case L'L':case L'M':case L'N':case L'O':case L'P':case L'Q':case L'R':case L'S':case L'T':case L'U':case L'V':case L'W':case L'X':case L'Y':case L'Z':return true;default:return false;}
else
switch(ch){case u8'A':case u8'B':case u8'C':case u8'D':case u8'E':case u8'F':case u8'G':case u8'H':case u8'I':case u8'J':case u8'K':case u8'L':case u8'M':case u8'N':case u8'O':case u8'P':case u8'Q':case u8'R':case u8'S':case u8'T':case u8'U':case u8'V':case u8'W':case u8'X':case u8'Y':case u8'Z':return true;default:return false;}
}
template<std::integral char_type>
inline constexpr bool is_c_digit(char_type ch) noexcept
{
if constexpr(std::same_as<char,char_type>)
switch(ch){case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':return true;default:return false;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'0':case L'1':case L'2':case L'3':case L'4':case L'5':case L'6':case L'7':case L'8':case L'9':return true;default:return false;}
else
switch(ch){case u8'0':case u8'1':case u8'2':case u8'3':case u8'4':case u8'5':case u8'6':case u8'7':case u8'8':case u8'9':return true;default:return false;}
}
template<std::integral char_type>
inline constexpr bool is_c_xdigit(char_type ch) noexcept
{
if constexpr(std::same_as<char,char_type>)
switch(ch){case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':return true;default:return false;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'0':case L'1':case L'2':case L'3':case L'4':case L'5':case L'6':case L'7':case L'8':case L'9':case L'a':case L'b':case L'c':case L'd':case L'e':case L'f':case L'A':case L'B':case L'C':case L'D':case L'E':case L'F':return true;default:return false;}
else
switch(ch){case u8'0':case u8'1':case u8'2':case u8'3':case u8'4':case u8'5':case u8'6':case u8'7':case u8'8':case u8'9':case u8'a':case u8'b':case u8'c':case u8'd':case u8'e':case u8'f':case u8'A':case u8'B':case u8'C':case u8'D':case u8'E':case u8'F':return true;default:return false;}
}
template<std::integral char_type>
inline constexpr bool is_c_punct(char_type ch) noexcept
{
if constexpr(std::same_as<char,char_type>)
switch(ch){case '!':case '\"':case '#':case '$':case '%':case '&':case '\'':case '(':case ')':case '*':case '+':case ',':case '-':case '.':case '/':case ':':case ';':case '<':case '=':case '>':case '?':case '@':case '[':case '\\':case ']':case '^':case '_':case '`':case '{':case '|':case '}':case '~':return true;default:return false;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'!':case L'\"':case L'#':case L'$':case L'%':case L'&':case L'\'':case L'(':case L')':case L'*':case L'+':case L',':case L'-':case L'.':case L'/':case L':':case L';':case L'<':case L'=':case L'>':case L'?':case L'@':case L'[':case L'\\':case L']':case L'^':case L'_':case L'`':case L'{':case L'|':case L'}':case L'~':return true;default:return false;}
else
switch(ch){case u8'!':case u8'\"':case u8'#':case u8'$':case u8'%':case u8'&':case u8'\'':case u8'(':case u8')':case u8'*':case u8'+':case u8',':case u8'-':case u8'.':case u8'/':case u8':':case u8';':case u8'<':case u8'=':case u8'>':case u8'?':case u8'@':case u8'[':case u8'\\':case u8']':case u8'^':case u8'_':case u8'`':case u8'{':case u8'|':case u8'}':case u8'~':return true;default:return false;}
}
template<std::integral char_type>
inline constexpr bool is_c_graph(char_type ch) noexcept
{
if constexpr(std::same_as<char,char_type>)
switch(ch){case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':case 'G':case 'H':case 'I':case 'J':case 'K':case 'L':case 'M':case 'N':case 'O':case 'P':case 'Q':case 'R':case 'S':case 'T':case 'U':case 'V':case 'W':case 'X':case 'Y':case 'Z':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':case 'q':case 'r':case 's':case 't':case 'u':case 'v':case 'w':case 'x':case 'y':case 'z':case '!':case '\"':case '#':case '$':case '%':case '&':case '\'':case '(':case ')':case '*':case '+':case ',':case '-':case '.':case '/':case ':':case ';':case '<':case '=':case '>':case '?':case '@':case '[':case '\\':case ']':case '^':case '_':case '`':case '{':case '|':case '}':case '~':return true;default:return false;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'0':case L'1':case L'2':case L'3':case L'4':case L'5':case L'6':case L'7':case L'8':case L'9':case L'A':case L'B':case L'C':case L'D':case L'E':case L'F':case L'G':case L'H':case L'I':case L'J':case L'K':case L'L':case L'M':case L'N':case L'O':case L'P':case L'Q':case L'R':case L'S':case L'T':case L'U':case L'V':case L'W':case L'X':case L'Y':case L'Z':case L'a':case L'b':case L'c':case L'd':case L'e':case L'f':case L'g':case L'h':case L'i':case L'j':case L'k':case L'l':case L'm':case L'n':case L'o':case L'p':case L'q':case L'r':case L's':case L't':case L'u':case L'v':case L'w':case L'x':case L'y':case L'z':case L'!':case L'\"':case L'#':case L'$':case L'%':case L'&':case L'\'':case L'(':case L')':case L'*':case L'+':case L',':case L'-':case L'.':case L'/':case L':':case L';':case L'<':case L'=':case L'>':case L'?':case L'@':case L'[':case L'\\':case L']':case L'^':case L'_':case L'`':case L'{':case L'|':case L'}':case L'~':return true;default:return false;}
else
switch(ch){case u8'0':case u8'1':case u8'2':case u8'3':case u8'4':case u8'5':case u8'6':case u8'7':case u8'8':case u8'9':case u8'A':case u8'B':case u8'C':case u8'D':case u8'E':case u8'F':case u8'G':case u8'H':case u8'I':case u8'J':case u8'K':case u8'L':case u8'M':case u8'N':case u8'O':case u8'P':case u8'Q':case u8'R':case u8'S':case u8'T':case u8'U':case u8'V':case u8'W':case u8'X':case u8'Y':case u8'Z':case u8'a':case u8'b':case u8'c':case u8'd':case u8'e':case u8'f':case u8'g':case u8'h':case u8'i':case u8'j':case u8'k':case u8'l':case u8'm':case u8'n':case u8'o':case u8'p':case u8'q':case u8'r':case u8's':case u8't':case u8'u':case u8'v':case u8'w':case u8'x':case u8'y':case u8'z':case u8'!':case u8'\"':case u8'#':case u8'$':case u8'%':case u8'&':case u8'\'':case u8'(':case u8')':case u8'*':case u8'+':case u8',':case u8'-':case u8'.':case u8'/':case u8':':case u8';':case u8'<':case u8'=':case u8'>':case u8'?':case u8'@':case u8'[':case u8'\\':case u8']':case u8'^':case u8'_':case u8'`':case u8'{':case u8'|':case u8'}':case u8'~':return true;default:return false;}
}
template<std::integral char_type>
inline constexpr bool is_c_print(char_type ch) noexcept
{
if constexpr(std::same_as<char,char_type>)
switch(ch){case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':case 'G':case 'H':case 'I':case 'J':case 'K':case 'L':case 'M':case 'N':case 'O':case 'P':case 'Q':case 'R':case 'S':case 'T':case 'U':case 'V':case 'W':case 'X':case 'Y':case 'Z':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':case 'q':case 'r':case 's':case 't':case 'u':case 'v':case 'w':case 'x':case 'y':case 'z':case '!':case '\"':case '#':case '$':case '%':case '&':case '\'':case '(':case ')':case '*':case '+':case ',':case '-':case '.':case '/':case ':':case ';':case '<':case '=':case '>':case '?':case '@':case '[':case '\\':case ']':case '^':case '_':case '`':case '{':case '|':case '}':case '~':case ' ':return true;default:return false;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'0':case L'1':case L'2':case L'3':case L'4':case L'5':case L'6':case L'7':case L'8':case L'9':case L'A':case L'B':case L'C':case L'D':case L'E':case L'F':case L'G':case L'H':case L'I':case L'J':case L'K':case L'L':case L'M':case L'N':case L'O':case L'P':case L'Q':case L'R':case L'S':case L'T':case L'U':case L'V':case L'W':case L'X':case L'Y':case L'Z':case L'a':case L'b':case L'c':case L'd':case L'e':case L'f':case L'g':case L'h':case L'i':case L'j':case L'k':case L'l':case L'm':case L'n':case L'o':case L'p':case L'q':case L'r':case L's':case L't':case L'u':case L'v':case L'w':case L'x':case L'y':case L'z':case L'!':case L'\"':case L'#':case L'$':case L'%':case L'&':case L'\'':case L'(':case L')':case L'*':case L'+':case L',':case L'-':case L'.':case L'/':case L':':case L';':case L'<':case L'=':case L'>':case L'?':case L'@':case L'[':case L'\\':case L']':case L'^':case L'_':case L'`':case L'{':case L'|':case L'}':case L'~':case L' ':return true;default:return false;}
else
switch(ch){case u8'0':case u8'1':case u8'2':case u8'3':case u8'4':case u8'5':case u8'6':case u8'7':case u8'8':case u8'9':case u8'A':case u8'B':case u8'C':case u8'D':case u8'E':case u8'F':case u8'G':case u8'H':case u8'I':case u8'J':case u8'K':case u8'L':case u8'M':case u8'N':case u8'O':case u8'P':case u8'Q':case u8'R':case u8'S':case u8'T':case u8'U':case u8'V':case u8'W':case u8'X':case u8'Y':case u8'Z':case u8'a':case u8'b':case u8'c':case u8'd':case u8'e':case u8'f':case u8'g':case u8'h':case u8'i':case u8'j':case u8'k':case u8'l':case u8'm':case u8'n':case u8'o':case u8'p':case u8'q':case u8'r':case u8's':case u8't':case u8'u':case u8'v':case u8'w':case u8'x':case u8'y':case u8'z':case u8'!':case u8'\"':case u8'#':case u8'$':case u8'%':case u8'&':case u8'\'':case u8'(':case u8')':case u8'*':case u8'+':case u8',':case u8'-':case u8'.':case u8'/':case u8':':case u8';':case u8'<':case u8'=':case u8'>':case u8'?':case u8'@':case u8'[':case u8'\\':case u8']':case u8'^':case u8'_':case u8'`':case u8'{':case u8'|':case u8'}':case u8'~':case u8' ':return true;default:return false;}
}
namespace details
{
inline constexpr char32_t to_c_upper_ascii_impl(char32_t ch) noexcept
{
constexpr char32_t alphanum{static_cast<char32_t>(26u)};
char32_t res{ch-U'a'};
if(res<alphanum)
return res+U'A';
return ch;
}
inline constexpr char32_t to_c_lower_ascii_impl(char32_t ch) noexcept
{
constexpr char32_t alphanum{static_cast<char32_t>(26u)};
char32_t res{ch-U'A'};
if(res<alphanum)
return res+U'a';
return ch;
}
}
template<std::integral char_type>
inline constexpr char_type to_c_lower(char_type ch) noexcept
{
using unsigned_char_type = std::make_unsigned_t<char_type>;
if constexpr(!::fast_io::details::is_ebcdic<char_type>)
return static_cast<char_type>(static_cast<unsigned_char_type>(details::to_c_lower_ascii_impl(static_cast<unsigned_char_type>(ch))));
else if constexpr(std::same_as<char,char_type>)
switch(ch){case 'A':return 'a';case 'B':return 'b';case 'C':return 'c';case 'D':return 'd';case 'E':return 'e';case 'F':return 'f';case 'G':return 'g';case 'H':return 'h';case 'I':return 'i';case 'J':return 'j';case 'K':return 'k';case 'L':return 'l';case 'M':return 'm';case 'N':return 'n';case 'O':return 'o';case 'P':return 'p';case 'Q':return 'q';case 'R':return 'r';case 'S':return 's';case 'T':return 't';case 'U':return 'u';case 'V':return 'v';case 'W':return 'w';case 'X':return 'x';case 'Y':return 'y';case 'Z':return 'z';default:return ch;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'A':return L'a';case L'B':return L'b';case L'C':return L'c';case L'D':return L'd';case L'E':return L'e';case L'F':return L'f';case L'G':return L'g';case L'H':return L'h';case L'I':return L'i';case L'J':return L'j';case L'K':return L'k';case L'L':return L'l';case L'M':return L'm';case L'N':return L'n';case L'O':return L'o';case L'P':return L'p';case L'Q':return L'q';case L'R':return L'r';case L'S':return L's';case L'T':return L't';case L'U':return L'u';case L'V':return L'v';case L'W':return L'w';case L'X':return L'x';case L'Y':return L'y';case L'Z':return L'z';default:return ch;}
}
template<std::integral char_type>
inline constexpr char_type to_c_upper(char_type ch) noexcept
{
using unsigned_char_type = std::make_unsigned_t<char_type>;
if constexpr(!::fast_io::details::is_ebcdic<char_type>)
return static_cast<char_type>(static_cast<unsigned_char_type>(details::to_c_upper_ascii_impl(static_cast<unsigned_char_type>(ch))));
else if constexpr(std::same_as<char,char_type>)
switch(ch){case 'a':return 'A';case 'b':return 'B';case 'c':return 'C';case 'd':return 'D';case 'e':return 'E';case 'f':return 'F';case 'g':return 'G';case 'h':return 'H';case 'i':return 'I';case 'j':return 'J';case 'k':return 'K';case 'l':return 'L';case 'm':return 'M';case 'n':return 'N';case 'o':return 'O';case 'p':return 'P';case 'q':return 'Q';case 'r':return 'R';case 's':return 'S';case 't':return 'T';case 'u':return 'U';case 'v':return 'V';case 'w':return 'W';case 'x':return 'X';case 'y':return 'Y';case 'z':return 'Z';default:return ch;}
else if constexpr(std::same_as<wchar_t,char_type>)
switch(ch){case L'a':return L'A';case L'b':return L'B';case L'c':return L'C';case L'd':return L'D';case L'e':return L'E';case L'f':return L'F';case L'g':return L'G';case L'h':return L'H';case L'i':return L'I';case L'j':return L'J';case L'k':return L'K';case L'l':return L'L';case L'm':return L'M';case L'n':return L'N';case L'o':return L'O';case L'p':return L'P';case L'q':return L'Q';case L'r':return L'R';case L's':return L'S';case L't':return L'T';case L'u':return L'U';case L'v':return L'V';case L'w':return L'W';case L'x':return L'X';case L'y':return L'Y';case L'z':return L'Z';default:return ch;}
}
/*
All Ascii based charset, only 6 character is supported
space (0x20, ' ')
form feed (0x0c, '\f')
line feed (0x0a, '\n')
carriage return (0x0d, '\r')
horizontal tab (0x09, '\t')
vertical tab (0x0b, '\v')
Any other exec-charset, besides these 6 characters, they can optionally support others, but too many are not allowed.
For EBCDIC NL should also get supported.
ASCII: space (0x20, ' '), EBCDIC:64
ASCII: form feed (0x0c, '\f'), EBCDIC:12
ASCII: line feed (0x0a, '\n'), EBCDIC:37
ASCII: carriage return (0x0d, '\r'), EBCDIC:13
ASCII: horizontal tab (0x09, '\t'), EBCDIC:5
ASCII: vertical tab (0x0b, '\v'), EBCDIC:11
EBCDIC specific: NL:21
*/
namespace details
{
inline constexpr bool is_c_space_wide_impl(wchar_t ch) noexcept
{
switch(ch)
{
case L'\f':case L'\n':case L'\r':
case L'\t':case L'\v':case L' ':return true;
default:
return false;
};
}
template<bool use_ebcdic,std::integral char_type>
inline constexpr bool is_c_space_impl(char_type ch) noexcept
{
if constexpr(use_ebcdic)
{
switch(ch)
{
case 5:case 11:case 12:case 13:
case 21:case 37:case 64:return true;
default:
return false;
};
}
else
{
if constexpr(std::unsigned_integral<std::remove_cvref_t<char_type>>)
{
using unsigned_t = char_type;
return (ch==0x20)|(static_cast<unsigned_t>(ch-0x9)<static_cast<unsigned_t>(0x5));
}
else
{
using unsigned_t = std::make_unsigned_t<char_type>;
unsigned_t const e(ch);
return (e==0x20)|(static_cast<unsigned_t>(e-0x9)<static_cast<unsigned_t>(0x5));
}
}
}
template<bool ebcdic,std::integral char_type>
inline constexpr auto is_c_space_tb_impl() noexcept
{
::fast_io::freestanding::array<bool,256u> tb;
for(std::size_t i{};i!=tb.size();++i)
tb[i]=is_c_space_impl<ebcdic>(static_cast<char_type>(i));
return tb;
}
template<bool ebcdic,std::integral char_type>
requires (sizeof(char_type)==1)
inline constexpr auto is_c_space_tb{is_c_space_tb_impl<ebcdic,char_type>()};
}
template<std::integral char_type>
inline constexpr bool is_c_space(char_type ch) noexcept
{
constexpr bool optimize_with_spacetb{sizeof(char_type)==1&&std::numeric_limits<std::uint_least8_t>::digits==8};
if constexpr(optimize_with_spacetb)
{
if constexpr(::fast_io::details::is_ebcdic<char_type>)
return details::is_c_space_tb<true,char8_t>[static_cast<std::make_unsigned_t<char_type>>(ch)];
else
return details::is_c_space_tb<false,char8_t>[static_cast<std::make_unsigned_t<char_type>>(ch)];
}
else
{
if constexpr(::fast_io::details::is_ebcdic<char_type>)
return details::is_c_space_impl<true>(ch);
else if constexpr(::std::same_as<char_type,wchar_t>&&::fast_io::details::wide_is_none_utf_endian)
return details::is_c_space_wide_impl(ch);
else
return details::is_c_space_impl<false>(static_cast<char32_t>(static_cast<std::make_unsigned_t<char_type>>(ch)));
}
}
/*
https://www.gnu.org/software/gcc/gcc-11/changes.html
A series of conditional expressions that compare the same variable can be transformed into a switch statement if each of them contains a comparison expression. Example:
int IsHTMLWhitespace(int aChar) {
return aChar == 0x0009 || aChar == 0x000A ||
aChar == 0x000C || aChar == 0x000D ||
aChar == 0x0020;
}
Let's just add this into this library
*/
namespace details
{
template<std::unsigned_integral char_type>
inline constexpr bool is_html_whitespace_ascii_impl(char_type ch) noexcept
{
switch(ch)
{
case 0x0009:case 0x000A:case 0x000C:case 0x000D:case 0x0020:return true;
default:return false;
}
}
/*
For EBCDIC NL should also get supported.
ASCII: space (0x20, ' '), EBCDIC:64
ASCII: form feed (0x0c, '\f'), EBCDIC:12
ASCII: line feed (0x0a, '\n'), EBCDIC:37
ASCII: carriage return (0x0d, '\r'), EBCDIC:13
ASCII: horizontal tab (0x09, '\t'), EBCDIC:5
EBCDIC specific: NL:21
*/
inline constexpr bool is_html_whitespace_ebcdic_impl(char32_t ch) noexcept
{
switch(ch)
{
case 5:case 12:case 13:
case 21:case 37:case 64:return true;
default:
return false;
};
}
inline constexpr bool is_html_whitespace_wide_impl(wchar_t ch) noexcept
{
switch(ch)
{
case L'\f':case L'\n':case L'\r':
case L'\t':case L' ':return true;
default:
return false;
};
}
}
template<std::integral char_type>
inline constexpr bool is_html_whitespace(char_type ch) noexcept
{
using unsigned_char_type = std::make_unsigned_t<char_type>;
if constexpr(::fast_io::details::is_ebcdic<char_type>)
{
return details::is_html_whitespace_ebcdic_impl(static_cast<unsigned_char_type>(ch));
}
else
{
if constexpr(sizeof(char_type)<=sizeof(char32_t))
{
return details::is_html_whitespace_ascii_impl(static_cast<char32_t>(static_cast<unsigned_char_type>(ch)));
}
else
{
return details::is_html_whitespace_ascii_impl(static_cast<unsigned_char_type>(ch));
}
}
}
template<std::integral char_type>
inline constexpr bool is_c_halfwidth(char_type ch) noexcept
{
using unsigned_char_type = std::make_unsigned_t<char_type>;
if constexpr(sizeof(char_type)<sizeof(char32_t))
{
return ch;
}
else if constexpr(!std::same_as<char_type,char32_t>&&sizeof(char_type)==sizeof(char32_t))
{
return is_c_halfwidth(static_cast<char32_t>(ch));
}
else if constexpr(std::signed_integral<char_type>)
{
return is_c_halfwidth(static_cast<unsigned_char_type>(ch));
}
else if constexpr(::std::same_as<char_type,wchar_t>&&::fast_io::details::wide_is_none_utf_endian)
{
constexpr unsigned_char_type halfwidth_exclaimation_mark_val{u8'!'};
constexpr unsigned_char_type num{94};
unsigned_char_type cht{ch};
cht=::fast_io::byte_swap(cht);
return static_cast<unsigned_char_type>(cht-halfwidth_exclaimation_mark_val)<num;
}
else
{
constexpr unsigned_char_type halfwidth_exclaimation_mark_val{u8'!'};
constexpr unsigned_char_type num{94};
return static_cast<unsigned_char_type>(ch-halfwidth_exclaimation_mark_val)<num;
}
}
template<std::integral char_type>
inline constexpr bool is_c_fullwidth(char_type ch) noexcept
{
using unsigned_char_type = std::make_unsigned_t<char_type>;
if constexpr(sizeof(char_type)<sizeof(char32_t))
{
return ch;
}
else if constexpr(!std::same_as<char_type,char32_t>&&sizeof(char_type)==sizeof(char32_t))
{
return is_c_fullwidth(static_cast<char32_t>(ch));
}
else if constexpr(std::signed_integral<char_type>)
{
return is_c_fullwidth(static_cast<unsigned_char_type>(ch));
}
else if constexpr(::std::same_as<char_type,wchar_t>&&::fast_io::details::wide_is_none_utf_endian)
{
constexpr unsigned_char_type halfwidth_exclaimation_mark_val{0xFF01};
constexpr unsigned_char_type num{94};
unsigned_char_type cht{ch};
cht=::fast_io::byte_swap(cht);
return static_cast<unsigned_char_type>(cht-halfwidth_exclaimation_mark_val)<num;
}
else
{
constexpr unsigned_char_type fullwidth_exclaimation_mark_val{0xFF01};
constexpr unsigned_char_type num{94};
return static_cast<unsigned_char_type>(ch-fullwidth_exclaimation_mark_val)<num;
}
}
/*
To do: to_c_fullwidth
*/
template<std::integral char_type>
inline constexpr char_type to_c_halfwidth(char_type ch) noexcept
{
using unsigned_char_type = std::make_unsigned_t<char_type>;
if constexpr(sizeof(char_type)<sizeof(char32_t))
{
return ch;
}
else if constexpr(!std::same_as<char_type,char32_t>&&sizeof(char_type)==sizeof(char32_t))
{
return static_cast<char_type>(to_c_halfwidth(static_cast<char32_t>(ch)));
}
else if constexpr(std::signed_integral<char_type>)
{
return static_cast<char_type>(to_c_halfwidth(static_cast<unsigned_char_type>(ch)));
}
else if constexpr(::std::same_as<char_type,wchar_t>&&::fast_io::details::wide_is_none_utf_endian)
{
constexpr unsigned_char_type fullwidth_exclaimation_mark_val{0xFF01};
constexpr unsigned_char_type num{94};
constexpr unsigned_char_type halfwidth_exclaimation_mark_val{u8'!'};
unsigned_char_type cht{ch};
cht=::fast_io::byte_swap(cht);
unsigned_char_type const umav{static_cast<unsigned_char_type>(cht-fullwidth_exclaimation_mark_val)};
if(umav<num)
{
return static_cast<unsigned_char_type>(umav+halfwidth_exclaimation_mark_val);
}
return cht;
}
else
{
constexpr unsigned_char_type fullwidth_exclaimation_mark_val{0xFF01};
constexpr unsigned_char_type num{94};
constexpr unsigned_char_type halfwidth_exclaimation_mark_val{u8'!'};
unsigned_char_type const umav{static_cast<unsigned_char_type>(ch-fullwidth_exclaimation_mark_val)};
if(umav<num)
{
return static_cast<unsigned_char_type>(umav+halfwidth_exclaimation_mark_val);
}
return ch;
}
}
}
namespace fast_io
{
namespace details
{
template<std::integral char_type>
inline constexpr char_type const* find_lf_simd_impl(char_type const*,char_type const*) noexcept;
template<bool ishtml,bool findnot,::std::forward_iterator Iter>
requires (::std::integral<::std::iter_value_t<Iter>>)
inline constexpr Iter find_space_impl(Iter,Iter);
}
template<::std::forward_iterator Iter>
requires (::std::integral<::std::iter_value_t<Iter>>)
inline constexpr Iter find_lf(Iter first, Iter last)
{
using char_type = ::std::iter_value_t<Iter>;
if constexpr(::std::contiguous_iterator<Iter>)
{
return ::fast_io::details::find_lf_simd_impl(::std::to_address(first),::std::to_address(last))-::std::to_address(first)+first;
}
else
{
return ::fast_io::freestanding::find(first,last,::fast_io::char_literal_v<u8'\n',char_type>);
}
}
template<::std::forward_iterator Iter>
requires (::std::integral<::std::iter_value_t<Iter>>)
inline constexpr Iter find_none_c_space(Iter begin,Iter end)
{
return ::fast_io::details::find_space_impl<false,true>(begin,end);
}
template<::std::forward_iterator Iter>
requires (::std::integral<::std::iter_value_t<Iter>>)
inline constexpr Iter find_c_space(Iter begin,Iter end)
{
return ::fast_io::details::find_space_impl<false,false>(begin,end);
}
template<::std::forward_iterator Iter>
requires (::std::integral<::std::iter_value_t<Iter>>)
inline constexpr Iter find_none_html_whitespace(Iter begin,Iter end)
{
return ::fast_io::details::find_space_impl<true,true>(begin,end);
}
template<::std::forward_iterator Iter>
requires (::std::integral<::std::iter_value_t<Iter>>)
inline constexpr Iter find_html_whitespace(Iter begin,Iter end)
{
return ::fast_io::details::find_space_impl<true,false>(begin,end);
}
}
@@ -0,0 +1,54 @@
#pragma once
namespace fast_io
{
template<std::integral src_char_type,
encoding_scheme src_scheme=execution_charset_encoding_scheme<src_char_type>(),
encoding_scheme dst_scheme=encoding_scheme::execution_charset>
struct basic_code_converter
{
using char_type=src_char_type;
inline static constexpr auto from_scheme = src_scheme;
inline static constexpr auto to_scheme = dst_scheme;
basic_mb_state<char_type,to_scheme> state;
};
using code_converter=basic_code_converter<char>;
using wcode_converter=basic_code_converter<wchar_t>;
using u8code_converter=basic_code_converter<char8_t>;
using u16code_converter=basic_code_converter<char16_t>;
using u32code_converter=basic_code_converter<char32_t>;
template<std::integral from_char_type,std::integral to_char_type,
encoding_scheme from_scheme,encoding_scheme to_scheme>
inline constexpr std::size_t deco_reserve_size(io_reserve_type_t<to_char_type,
basic_code_converter<from_char_type,from_scheme,to_scheme>>,
basic_code_converter<from_char_type,from_scheme,to_scheme>&,std::size_t from_size) noexcept
{
return details::cal_decorated_reserve_size<sizeof(from_char_type),sizeof(to_char_type)>(from_size);
}
template<encoding_scheme from_scheme,encoding_scheme to_scheme,
::std::contiguous_iterator from_iter,::std::contiguous_iterator to_iter>
inline constexpr to_iter deco_reserve_define(io_reserve_type_t<::std::iter_value_t<to_iter>,
basic_code_converter<::std::iter_value_t<from_iter>,from_scheme,to_scheme>>,
basic_code_converter<::std::iter_value_t<from_iter>,from_scheme,to_scheme>& conv,from_iter src_first,from_iter src_last,to_iter dst) noexcept
{
if constexpr(std::is_pointer_v<from_iter>&&std::is_pointer_v<to_iter>)
return details::codecvt::general_code_cvt<from_scheme,to_scheme>(conv.state,src_first,src_last,dst);
else if constexpr(std::is_pointer_v<to_iter>)
return details::codecvt::general_code_cvt<from_scheme,to_scheme>(conv.state,
::std::to_address(src_first),
::std::to_address(src_last),
dst);
else
{
return dst+(details::codecvt::general_code_cvt<from_scheme,to_scheme>(conv.state,
::std::to_address(src_first),
::std::to_address(src_last),
::std::to_address(dst))-::std::to_address(dst));
}
}
}
@@ -0,0 +1,46 @@
#pragma once
namespace fast_io
{
namespace details::codecvt::gb18030
{
template<typename T>
requires (sizeof(T)==1)
inline constexpr std::size_t get_gb18030_invalid_code_units(T* p_dst) noexcept;
template<typename T>
requires (sizeof(T)==1)
inline constexpr std::size_t lookup_uni_to_gb18030(char32_t cdpt, T* p_dst) noexcept;
template<typename T>
requires (sizeof(T)==1)
inline constexpr std::size_t get_gb18030_code_units_unhappy(char32_t u32, T* p_dst) noexcept;
template<typename T>
requires (sizeof(T)==1)
inline constexpr std::size_t get_gb18030_code_units(char32_t cdpt, T* p_dst) noexcept;
template<typename T>
requires (sizeof(T)==1)
struct gb18030_advance_unchecked_result
{
char32_t cdpt;
char8_t adv;
};
inline constexpr char32_t lookup_gb18030_to_uni4_func(char32_t index) noexcept;
inline constexpr char32_t utf32cp_by_gb18030_index(char32_t index) noexcept;
template<typename T>
requires (sizeof(T)==1)
inline constexpr gb18030_advance_unchecked_result<T> gb18030_advance_unchecked(T const* src) noexcept;
template<typename T>
requires (sizeof(T)==1)
inline constexpr gb18030_advance_unchecked_result<T> gb18030_advance(T const* src,std::size_t sz) noexcept;
}
}
@@ -0,0 +1,569 @@
#pragma once
namespace fast_io
{
namespace details::codecvt
{
template<encoding_scheme encoding,typename T>
inline constexpr auto general_advance(T* src_first,std::size_t sz) noexcept
{
if constexpr(encoding_scheme::utf_ebcdic==encoding)
return utf_ebcdic_advance(src_first,sz);
else
return gb18030::gb18030_advance(src_first,sz);
}
template<encoding_scheme encoding,typename T>
inline constexpr std::size_t get_general_invalid_code_units(T* dst) noexcept
{
if constexpr(encoding==encoding_scheme::utf_ebcdic)
return get_utf_ebcdic_invalid_code_units(dst);
else if constexpr(encoding==encoding_scheme::gb18030)
return gb18030::get_gb18030_invalid_code_units(dst);
else
{
if constexpr(sizeof(T)>=2)
{
if constexpr(encoding_is_utf(encoding)&&!is_native_scheme(encoding))
{
constexpr T val{byte_swap(static_cast<T>(0xFFFD))};
*dst=val;
}
else
*dst=static_cast<T>(0xFFFD);
return 1;
}
else
return get_utf8_invalid_code_units(dst);
}
}
template<std::integral char_type>
inline constexpr encoding_scheme get_execution_charset_encoding_scheme(encoding_scheme scheme) noexcept
{
if(scheme!=encoding_scheme::execution_charset)
return scheme;
return execution_charset_encoding_scheme<char_type>();
}
template<
encoding_scheme src_encoding=encoding_scheme::execution_charset,
encoding_scheme encoding=encoding_scheme::execution_charset,
std::integral src_char_type,std::integral dest_char_type>
requires (sizeof(src_char_type)<=4 &&sizeof(dest_char_type)<=4)
inline constexpr code_cvt_result<src_char_type,dest_char_type> general_code_cvt(src_char_type const* src_first,src_char_type const* src_last,dest_char_type* __restrict dst) noexcept
{
if constexpr(src_encoding==encoding_scheme::execution_charset)
{
return general_code_cvt<get_execution_charset_encoding_scheme<src_char_type>(src_encoding),
encoding>(src_first,src_last,dst);
}
else if constexpr(encoding==encoding_scheme::execution_charset)
{
return general_code_cvt<src_encoding,
get_execution_charset_encoding_scheme<dest_char_type>(encoding)>(src_first,src_last,dst);
}
else if constexpr(sizeof(src_char_type)==sizeof(dest_char_type)&&src_encoding==encoding)
{
std::size_t diff{static_cast<std::size_t>(src_last-src_first)};
non_overlapped_copy_n(src_first,diff,dst);
return {src_last,dst+diff};
}
else if constexpr(sizeof(src_char_type)==sizeof(dest_char_type)&&
((src_encoding==encoding_scheme::utf_le&&encoding==encoding_scheme::utf_be)||
(src_encoding==encoding_scheme::utf_be&&encoding==encoding_scheme::utf_le)))
{
if constexpr(sizeof(src_char_type)==1)
{
return general_code_cvt<encoding_scheme::utf,encoding_scheme::utf>(src_first,src_last,dst);
}
else
{
for(;src_first!=src_last;++src_first)
*dst=byte_swap(*src_first);
return {src_first,dst};
}
}
else if constexpr(sizeof(src_char_type)==4)
{
static_assert(src_encoding==encoding_scheme::utf_be||src_encoding==encoding_scheme::utf_le);
for(;src_first!=src_last;++src_first)
dst+=get_utf_code_units<encoding>(static_cast<char32_t>(*src_first),dst);
return {src_last,dst};
}
else if constexpr(sizeof(src_char_type)==2)
{
static_assert(src_encoding==encoding_scheme::utf_be||src_encoding==encoding_scheme::utf_le);
/*
Referenced from
https://stackoverflow.com/questions/23919515/how-to-convert-from-utf-16-to-utf-32-on-linux-with-std-library
*/
for(;src_first!=src_last;++src_first)
{
char16_t code{static_cast<char16_t>(*src_first)};
if constexpr(!is_native_scheme(src_encoding))
code=byte_swap(code);
if(is_utf16_surrogate(code))[[unlikely]]
{
if(is_utf16_high_surrogate(code))
{
if(src_first+1==src_last)
{
break;
}
char16_t code1{static_cast<char16_t>(*++src_first)};
if constexpr(!is_native_scheme(src_encoding))
code1=byte_swap(code1);
if(is_utf16_low_surrogate(code1))
{
if constexpr(sizeof(dest_char_type)==4)
{
*dst = utf16_surrogate_to_utf32(code,code1);
++dst;
}
else
dst+=get_utf_code_units<encoding>(utf16_surrogate_to_utf32(code,code1),dst);
continue;
}
}
if constexpr(sizeof(dest_char_type)==4)
{
if constexpr(is_native_scheme(encoding))
*dst=static_cast<dest_char_type>(0xFFFD);
else
*dst=static_cast<dest_char_type>(0xFDFF0000);
++dst;
}
else
{
dst+=get_general_invalid_code_units<encoding>(dst);
}
}
else[[likely]]
{
if constexpr(sizeof(dest_char_type)==4)
{
if constexpr(src_encoding==encoding)
*dst=static_cast<dest_char_type>(code);
else
*dst=byte_swap(static_cast<dest_char_type>(code));
++dst;
}
else
dst+=get_utf_code_units<encoding>(code,dst);
}
}
return {src_first,dst};
}
else
{
#if (defined(_MSC_VER)&&defined(_M_AMD64)&&!defined(__clang__)) || (defined(__SSE__) && defined(__x86_64__) && __cpp_lib_is_constant_evaluated>=201811L)
if constexpr(src_encoding!=encoding_scheme::utf_ebcdic&&encoding!=encoding_scheme::utf_ebcdic&&1==sizeof(src_char_type)
&&(1==sizeof(dest_char_type)||encoding_is_utf(encoding)))
{
if (!std::is_constant_evaluated())
{
constexpr std::size_t m128i_size{16};
while(m128i_size < static_cast<std::size_t>(src_last-src_first))
{
if (static_cast<char8_t>(*src_first) < 0x80)
{
auto [new_src,new_dst]= convert_ascii_with_sse(src_first, dst);
src_first=new_src;
dst=new_dst;
}
else
{
if constexpr(src_encoding==encoding_scheme::gb18030)
{
auto [code,adv] = gb18030::gb18030_advance_unchecked(src_first);
src_first+=adv;
if constexpr(sizeof(dest_char_type)==4)
{
*dst=code;
++dst;
}
else
dst+=get_utf_code_units<encoding>(code,dst);
}
else
{
auto [src,code] = advance_with_big_table_unchecked(src_first);
src_first=src;
if constexpr(sizeof(dest_char_type)==4)
{
*dst=code;
++dst;
}
else
dst+=get_utf_code_units<encoding>(code,dst);
}
}
}
}
}
#endif
for(;src_first!=src_last;)
if constexpr(src_encoding==encoding_scheme::utf_ebcdic)
{
auto [code,adv]=general_advance<src_encoding>(src_first,src_last-src_first);
if(adv==static_cast<char8_t>(-1))
break;
src_first+=adv;
if constexpr(sizeof(dest_char_type)==4)
{
*dst=code;
if constexpr(encoding_is_utf(encoding)&&!is_native_scheme(encoding))
*dst=byte_swap(*dst);
++dst;
}
else
{
dst+=get_utf_code_units<encoding>(code,dst);
}
}
else
{
if (static_cast<char8_t>(*src_first) < 0x80)
{
if constexpr(encoding_scheme::utf_ebcdic==encoding)
*dst= static_cast<dest_char_type>(bm_i8_to_ebcdic[*src_first]);
else
*dst= static_cast<char8_t>(*src_first);
if constexpr(sizeof(dest_char_type)!=1&&encoding_is_utf(encoding)&&!is_native_scheme(encoding))
*dst=byte_swap(*dst);
++src_first;
++dst;
}
else
{
if constexpr(src_encoding!=encoding_scheme::utf)
{
auto [code,adv]=general_advance<src_encoding>(src_first,src_last-src_first);
if(adv==static_cast<char8_t>(-1))
break;
src_first+=adv;
if constexpr(sizeof(dest_char_type)==4)
{
*dst=code;
if constexpr(encoding_is_utf(encoding)&&!is_native_scheme(encoding))
*dst=byte_swap(*dst);
++dst;
}
else
{
dst+=get_utf_code_units<encoding>(code,dst);
}
}
else
{
auto [failed,src,code] = advance_with_big_table(src_first, src_last);
if(failed)
break;
src_first=src;
if constexpr(sizeof(dest_char_type)==4)
{
*dst=code;
if constexpr(encoding_is_utf(encoding)&&!is_native_scheme(encoding))
*dst=byte_swap(*dst);
++dst;
}
else
dst+=get_utf_code_units<encoding>(code,dst);
}
}
}
return {src_first,dst};
}
}
template<
encoding_scheme src_encoding=encoding_scheme::execution_charset,
encoding_scheme encoding=encoding_scheme::execution_charset,typename state_type,
std::integral src_char_type,std::integral dest_char_type>
requires (sizeof(src_char_type)<=4 &&sizeof(dest_char_type)<=4)
inline constexpr dest_char_type* general_code_cvt(state_type& __restrict state,src_char_type const* src_first,src_char_type const* src_last,dest_char_type* __restrict dst) noexcept
{
if constexpr(src_encoding==encoding_scheme::execution_charset)
{
return general_code_cvt<get_execution_charset_encoding_scheme<src_char_type>(src_encoding),
encoding>(state,src_first,src_last,dst);
}
else if constexpr(encoding==encoding_scheme::execution_charset)
{
return general_code_cvt<src_encoding,
get_execution_charset_encoding_scheme<dest_char_type>(encoding)>(state,src_first,src_last,dst);
}
else if constexpr(sizeof(src_char_type)==4)
{
static_assert(src_encoding==encoding_scheme::utf);
return general_code_cvt<src_encoding,encoding>(src_first,src_last,dst).dst;
}
else if constexpr(sizeof(src_char_type)==2)
{
static_assert(src_encoding==encoding_scheme::utf);
if(state.state)
{
if(src_first==src_last)
return dst;
char16_t low{state.value};
if constexpr(!is_native_scheme(src_encoding))
low=byte_swap(low);
char16_t v{static_cast<char16_t>(*src_first)};
if constexpr(!is_native_scheme(src_encoding))
v=byte_swap(v);
if(is_utf16_low_surrogate(v))
{
if constexpr(sizeof(dest_char_type)==4)
{
*dst = utf16_surrogate_to_utf32(low,v);
if constexpr(!is_native_scheme(encoding))
*dst = byte_swap(*dst);
++dst;
}
else
dst+=get_utf_code_units<encoding>(utf16_surrogate_to_utf32(low,v),dst);
++src_first;
}
else[[unlikely]]
{
if constexpr(sizeof(dest_char_type)==4)
{
if constexpr(is_native_scheme(encoding))
*dst=static_cast<dest_char_type>(0xFFFD);
else
*dst=static_cast<dest_char_type>(0xFDFF0000);
++dst;
}
else
dst+=get_general_invalid_code_units<encoding>(dst);
}
}
auto [new_src,new_dst]=general_code_cvt<src_encoding,encoding>(src_first,src_last,dst);
if((state.state=(new_src!=src_last)))
state.value=*new_src;
return new_dst;
}
else if constexpr(sizeof(src_char_type)==1)
{
std::size_t const state_size{static_cast<std::size_t>(state.size)};
if(state_size)
{
std::size_t src_diff{static_cast<std::size_t>(src_last-src_first)};
if(src_diff==0)
return dst;
constexpr std::size_t state_bytes{8};
constexpr std::size_t state_bytesm1{state_bytes-1};
std::size_t remain_unsolved{state_bytes-state_size};
char8_t bytes[state_bytes];
non_overlapped_copy_n(state.bytes,state_bytesm1,bytes);
if(src_diff<remain_unsolved)
remain_unsolved=src_diff;
non_overlapped_copy_n(src_first,remain_unsolved,bytes+state_size);
std::size_t total_bytes{state_size+remain_unsolved};
if constexpr(src_encoding==encoding_scheme::utf)
{
auto [failed,bytes_src,code] = advance_with_big_table(bytes, bytes+total_bytes);
if(failed)
{
non_overlapped_copy_n(bytes,state_bytesm1,state.bytes);
state.size=static_cast<char8_t>(total_bytes);
return dst;
}
if constexpr(sizeof(dest_char_type)==4)
{
*dst=code;
if constexpr(!is_native_scheme(encoding))
*dst=byte_swap(*dst);
++dst;
}
else
dst+=get_utf_code_units<encoding>(code,dst);
src_first+=static_cast<std::size_t>(bytes_src-bytes-state_size);
}
else
{
auto [code,adv]=general_advance<src_encoding>(bytes,total_bytes);
if(adv==static_cast<char8_t>(-1))
{
non_overlapped_copy_n(bytes,state_bytesm1,state.bytes);
state.size=static_cast<char8_t>(total_bytes);
return dst;
}
if constexpr(sizeof(dest_char_type)==4)
{
*dst=code;
if constexpr(!is_native_scheme(encoding))
*dst=byte_swap(*dst);
++dst;
}
else
dst+=get_utf_code_units<encoding>(code,dst);
src_first+=static_cast<std::size_t>(static_cast<std::size_t>(adv)-state_size);
}
}
auto [new_src,new_dst]=general_code_cvt<src_encoding,encoding>(src_first,src_last,dst);
std::size_t diff{static_cast<std::size_t>(src_last-new_src)};
state.size=static_cast<char8_t>(diff);
non_overlapped_copy_n(new_src,diff,state.bytes);
return new_dst;
}
else
return dst;
}
template<
encoding_scheme src_encoding=encoding_scheme::execution_charset,
encoding_scheme encoding=encoding_scheme::execution_charset,
std::integral src_char_type,std::integral dest_char_type>
requires (sizeof(src_char_type)<=4 &&sizeof(dest_char_type)<=4)
inline constexpr dest_char_type* general_code_cvt_full(src_char_type const* src_first,src_char_type const* src_last,dest_char_type* __restrict dst) noexcept
{
if constexpr(src_encoding==encoding_scheme::execution_charset)
{
constexpr auto src_scheme = get_execution_charset_encoding_scheme<src_char_type>(src_encoding);
constexpr auto dst_scheme = get_execution_charset_encoding_scheme<dest_char_type>(encoding);
return general_code_cvt_full<src_scheme,
dst_scheme>(src_first,src_last,dst);
}
else
{
auto [src,new_dst]=general_code_cvt<src_encoding,encoding>(src_first,src_last,dst);
if(src!=src_last)
{
if constexpr(sizeof(dest_char_type)==4)
{
if constexpr(is_native_scheme(encoding))
*new_dst=static_cast<dest_char_type>(0xFFFD);
else
*new_dst=static_cast<dest_char_type>(0xFDFF0000);
++new_dst;
}
else
new_dst+=get_general_invalid_code_units<encoding>(dst);
}
return new_dst;
}
}
template<typename T>
concept type_has_value_type = requires(T)
{
typename T::value_type;
};
template<typename T>
inline constexpr bool print_alias_test_codecvt_impl() noexcept
{
if constexpr(alias_printable<T>)
{
using alias_type = decltype(print_alias_define(io_alias,*static_cast<T const*>(static_cast<void const*>(nullptr))));
if constexpr(type_has_value_type<alias_type>)
{
using value_type = typename alias_type::value_type;
return std::same_as<alias_type,basic_io_scatter_t<value_type>>;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
namespace manipulators
{
template<
encoding_scheme src_scheme,
encoding_scheme dst_scheme,
std::integral char_type>
struct code_cvt_t
{
using manip_tag = manip_tag_t;
basic_io_scatter_t<char_type> reference;
};
template<
encoding_scheme src_scheme=encoding_scheme::execution_charset,
encoding_scheme dst_scheme=encoding_scheme::execution_charset,
typename T>
requires (::fast_io::details::codecvt::print_alias_test_codecvt_impl<T>())
constexpr auto code_cvt(T const& t) noexcept
{
using value_type = typename decltype(print_alias_define(io_alias,t))::value_type;
return code_cvt_t<src_scheme,dst_scheme,value_type>{print_alias_define(io_alias,t)};
}
template<
encoding_scheme src_scheme=encoding_scheme::execution_charset,
encoding_scheme dst_scheme=encoding_scheme::execution_charset,
std::integral char_type>
constexpr auto code_cvt(basic_io_scatter_t<char_type> t) noexcept
{
return code_cvt_t<src_scheme,dst_scheme,char_type>{t};
}
template<
encoding_scheme src_scheme=encoding_scheme::execution_charset,
encoding_scheme dst_scheme=encoding_scheme::execution_charset,
std::integral char_type,std::size_t N>
constexpr auto code_cvt(small_scatter_t<char_type,N> t) noexcept
{
return code_cvt_t<src_scheme,dst_scheme,char_type>{{t.base,t.len}};
}
template<
encoding_scheme src_scheme=encoding_scheme::execution_charset,
encoding_scheme dst_scheme=encoding_scheme::execution_charset,
::std::integral char_type>
constexpr auto code_cvt_os_c_str(char_type const* cstr) noexcept
{
return ::fast_io::manipulators::code_cvt<src_scheme,dst_scheme>(::fast_io::manipulators::os_c_str(cstr));
}
template<
encoding_scheme src_scheme=encoding_scheme::execution_charset,
encoding_scheme dst_scheme=encoding_scheme::execution_charset,
::std::integral char_type>
constexpr auto code_cvt_os_c_str(char_type const* cstr,::std::size_t n) noexcept
{
return ::fast_io::manipulators::code_cvt<src_scheme,dst_scheme>(::fast_io::mnp::os_c_str(cstr,n));
}
template<
encoding_scheme src_scheme=encoding_scheme::execution_charset,
encoding_scheme dst_scheme=encoding_scheme::execution_charset,
std::integral src_char_type,
std::integral dst_char_type>
inline constexpr std::size_t print_reserve_size(
io_reserve_type_t<dst_char_type,code_cvt_t<src_scheme,dst_scheme,src_char_type>>,
code_cvt_t<src_scheme,dst_scheme,src_char_type> v) noexcept
{
return details::cal_full_reserve_size<sizeof(src_char_type),sizeof(dst_char_type)>(v.reference.len);
}
template<
encoding_scheme src_scheme=encoding_scheme::execution_charset,
encoding_scheme dst_scheme=encoding_scheme::execution_charset,
std::integral src_char_type,
::std::integral char_type>
inline constexpr char_type* print_reserve_define(
io_reserve_type_t<char_type,code_cvt_t<src_scheme,dst_scheme,src_char_type>>,
char_type* iter,
code_cvt_t<src_scheme,dst_scheme,src_char_type> v) noexcept
{
return details::codecvt::general_code_cvt_full(v.reference.base,v.reference.base+v.reference.len,iter);
}
}
}
@@ -0,0 +1,27 @@
#pragma once
#include"gb18030.h"
#include"utf_ebcdic.h"
#include"utf_util_table.h"
#include"utf.h"
#include"general.h"
#include"code_cvt.h"
namespace fast_io
{
template<std::integral char_type,std::integral cross_char_type>
inline constexpr auto status_io_print_forward(io_alias_type_t<char_type>,cross_code_cvt_t<cross_char_type> const& ccvt) noexcept
{
if constexpr(std::same_as<char_type,cross_char_type>)
{
return ccvt.scatter;
}
else
{
return ::fast_io::mnp::code_cvt_t<encoding_scheme::execution_charset,encoding_scheme::execution_charset,cross_char_type>{ccvt.scatter};
}
}
}
@@ -0,0 +1,632 @@
#pragma once
namespace fast_io
{
struct u8utf_mb_state
{
char8_t bytes[7];
char8_t size{};
explicit inline constexpr operator bool() const noexcept
{
return static_cast<bool>(size);
}
};
struct u16utf_mb_state
{
char16_t value;
bool state{};
explicit inline constexpr operator bool() const noexcept
{
return state;
}
};
struct u32utf_mb_state
{
explicit inline constexpr operator bool() const noexcept
{
return false;
}
};
template<std::integral char_type>
requires (sizeof(char_type)<=4)
using basic_utf_mb_state = std::conditional_t<sizeof(char_type)==4,u32utf_mb_state,
std::conditional_t<sizeof(char_type)==2,u16utf_mb_state,u8utf_mb_state>>;
using utf_mb_state = basic_utf_mb_state<char>;
using wutf_mb_state = basic_utf_mb_state<wchar_t>;
using gb18030_mb_state = utf_mb_state;
using ebcdic_mb_state = utf_mb_state;
using execution_charset_mb_state = utf_mb_state;
using wexecution_charset_mb_state = wutf_mb_state;
enum class encoding_scheme
{
execution_charset,
utf_le,
utf_be,
gb18030,
utf_ebcdic,
utf=std::endian::big==std::endian::native?utf_be:(std::endian::little==std::endian::native?utf_le:5)
};
/*
CppCon 2018: Bob Steagall “Fast Conversion From UTF-8 with C++, DFAs, and SSE Intrinsics”
https://www.youtube.com/watch?v=5FQ87-Ecb-A
https://github.com/BobSteagall/utf_utils/blob/master/src/utf_utils.cpp
*/
namespace details
{
template<std::size_t src_char_type_size,std::size_t dest_char_type_size>
requires ((dest_char_type_size<=4)&&(src_char_type_size<=4))
inline constexpr std::size_t cal_full_reserve_size(std::size_t internal_size) noexcept
{
constexpr std::size_t external_max{std::numeric_limits<std::size_t>::max()/dest_char_type_size};
constexpr std::size_t internal_max{std::numeric_limits<std::size_t>::max()/src_char_type_size};
if constexpr(src_char_type_size==4)
{
if constexpr(dest_char_type_size==4)
{
constexpr std::size_t imax{external_max};
if(internal_size>=imax)
fast_terminate();
return internal_size;
}
else if constexpr(dest_char_type_size==2)
{
constexpr std::size_t imax{external_max/2};
if(internal_size>=imax)
fast_terminate();
return internal_size*2;
}
else
{
constexpr std::size_t imax{external_max/8};
if(internal_size>=imax)
fast_terminate();
return internal_size*8;
}
}
else if constexpr(src_char_type_size==2)
{
if constexpr(dest_char_type_size==4)
{
constexpr std::size_t imax{external_max};
if(internal_size>=imax)
fast_terminate();
return internal_size;
}
else if constexpr(dest_char_type_size==2)
{
constexpr std::size_t imax{external_max/2};
if(internal_size>=imax)
fast_terminate();
return internal_size*2;
}
else
{
constexpr std::size_t imax{external_max/8};
if(internal_size>=imax)
fast_terminate();
return internal_size*8;
}
}
else
{
if constexpr(dest_char_type_size==4)
{
constexpr std::size_t imax{external_max};
if(internal_size>=imax)
fast_terminate();
return internal_size;
}
else if constexpr(dest_char_type_size==2)
{
constexpr std::size_t imax{internal_max/2};
if(internal_size>=imax)
fast_terminate();
return 2*internal_size;
}
else
{
constexpr std::size_t imax{internal_max/8};
if(internal_size>=imax)
fast_terminate();
return 8*internal_size;
}
}
}
template<std::size_t src_char_type_size,std::size_t dest_char_type_size>
requires ((dest_char_type_size<=4)&&(src_char_type_size<=4))
inline constexpr std::size_t cal_decorated_reserve_size(std::size_t internal_size) noexcept
{
constexpr std::size_t external_max{std::numeric_limits<std::size_t>::max()/dest_char_type_size};
constexpr std::size_t internal_max{std::numeric_limits<std::size_t>::max()/src_char_type_size};
if constexpr(src_char_type_size==4)
{
if constexpr(dest_char_type_size==4)
{
constexpr std::size_t imax{external_max};
if(internal_size>=imax)
fast_terminate();
return internal_size;
}
else if constexpr(dest_char_type_size==2)
{
constexpr std::size_t imax{external_max/2};
if(internal_size>=imax)
fast_terminate();
return internal_size*2;
}
else
{
constexpr std::size_t imax{external_max/8};
if(internal_size>=imax)
fast_terminate();
return internal_size*8;
}
}
else if constexpr(src_char_type_size==2)
{
if constexpr(dest_char_type_size==4)
{
constexpr std::size_t imax{external_max-1};
if(internal_size>=imax)
fast_terminate();
return internal_size+1;
}
else if constexpr(dest_char_type_size==2)
{
constexpr std::size_t imax{external_max/2-1};
if(internal_size>=imax)
fast_terminate();
return internal_size*2+2;
}
else
{
constexpr std::size_t imax{external_max/8-1};
if(internal_size>=imax)
fast_terminate();
return internal_size*8+8;
}
}
else
{
if constexpr(dest_char_type_size==4)
{
constexpr std::size_t imax{external_max-7};
if(internal_size>=imax)
fast_terminate();
return internal_size+7;
}
else if constexpr(dest_char_type_size==2)
{
constexpr std::size_t imax{internal_max/2-7};
if(internal_size>=imax)
fast_terminate();
return 2*internal_size+14;
}
else
{
constexpr std::size_t imax{internal_max/8-7};
if(internal_size>=imax)
fast_terminate();
return 8*internal_size+56;
}
}
}
#if defined(__GNUC_EXECUTION_CHARSET_NAME) || defined(__GNUC_WIDE_EXECUTION_CHARSET_NAME)
template<std::size_t N1,std::size_t N2>
inline constexpr bool execution_charset_is(char const (&str)[N1],char8_t const (&encoding)[N2]) noexcept
{
if constexpr(N1!=N2)
{
return false;
}
else
{
for(std::size_t i{};i!=N1;++i)
{
char8_t ch{::fast_io::char_category::to_c_upper(static_cast<char8_t>(str[i]))};
char8_t ch1{::fast_io::char_category::to_c_upper(static_cast<char8_t>(encoding[i]))};
if(ch!=ch1)
{
return false;
}
}
return true;
}
}
#endif
}
template<std::integral char_type>
inline constexpr encoding_scheme execution_charset_encoding_scheme() noexcept
{
using char_type_no_cvref_t = std::remove_cvref_t<char_type>;
if constexpr(::fast_io::details::is_ebcdic<char_type_no_cvref_t>)
return encoding_scheme::utf_ebcdic;
else
{
if constexpr(std::same_as<char_type_no_cvref_t,char>)
{
#if defined(_MSVC_EXECUTION_CHARACTER_SET)
if constexpr(_MSVC_EXECUTION_CHARACTER_SET == 936 || _MSVC_EXECUTION_CHARACTER_SET == 54936)
{
return encoding_scheme::gb18030;
}
else
{
return encoding_scheme::utf;
}
#elif defined(__GNUC_EXECUTION_CHARSET_NAME)
if constexpr(::fast_io::details::execution_charset_is(__GNUC_EXECUTION_CHARSET_NAME,u8"GB18030")
|| ::fast_io::details::execution_charset_is(__GNUC_EXECUTION_CHARSET_NAME,u8"GBK"))
{
return encoding_scheme::gb18030;
}
else
{
return encoding_scheme::utf;
}
#else
return encoding_scheme::utf;
#endif
}
else if constexpr(std::same_as<char_type_no_cvref_t,wchar_t>)
{
#if defined(__GNUC_WIDE_EXECUTION_CHARSET_NAME)
if constexpr(sizeof(wchar_t)==1&&
(::fast_io::details::execution_charset_is(__GNUC_WIDE_EXECUTION_CHARSET_NAME,u8"GB18030")
|| ::fast_io::details::execution_charset_is(__GNUC_WIDE_EXECUTION_CHARSET_NAME,u8"GBK")))
{
return encoding_scheme::gb18030;
}
else
{
if constexpr(::fast_io::details::wide_is_none_utf_endian)
{
if constexpr(encoding_scheme::utf==encoding_scheme::utf_le)
{
return encoding_scheme::utf_be;
}
else
{
return encoding_scheme::utf_le;
}
}
return encoding_scheme::utf;
}
#else
return encoding_scheme::utf;
#endif
}
else
{
return encoding_scheme::utf;
}
}
}
template<std::integral char_type,encoding_scheme scheme=execution_charset_encoding_scheme<char_type>()>
using basic_mb_state=basic_utf_mb_state<char_type>;
template<std::integral src_char_type,std::integral dest_char_type>
struct code_cvt_result
{
src_char_type const* src;
dest_char_type* dst;
};
namespace details::codecvt
{
inline constexpr bool encoding_is_utf(encoding_scheme scheme) noexcept
{
return scheme==encoding_scheme::utf||scheme==encoding_scheme::utf_le||scheme==encoding_scheme::utf_be;
}
inline constexpr bool is_native_scheme(encoding_scheme scheme) noexcept
{
return scheme==encoding_scheme::utf;
}
template<std::integral T>
requires (sizeof(T)==1)
inline constexpr std::size_t get_utf8_invalid_code_units(T* dst) noexcept
{
*dst = static_cast<T>(0xEF);
dst[1] = static_cast<T>(0xBF);
dst[2] = static_cast<T>(0xBD);
return 3;
}
template<encoding_scheme scheme,std::integral T>
requires (sizeof(T)<=4)
inline constexpr std::size_t get_utf_code_units(char32_t cdpt,T* dst) noexcept
{
if constexpr(scheme==encoding_scheme::utf_ebcdic)
{
return get_utf_ebcdic_code_units(cdpt,dst);
}
else if constexpr(scheme==encoding_scheme::gb18030)
{
return gb18030::get_gb18030_code_units(cdpt,dst);
}
else
{
if constexpr(sizeof(T)==sizeof(char32_t))
{
if constexpr(is_native_scheme(scheme))
*dst=static_cast<T>(cdpt);
else
*dst=byte_swap(static_cast<T>(cdpt));
return 1;
}
else if constexpr(sizeof(T)==sizeof(char16_t))
{
if (cdpt < 0x10000)
{
if constexpr(is_native_scheme(scheme))
*dst = static_cast<T>(cdpt);
else
*dst = byte_swap(static_cast<T>(cdpt));
return 1;
}
else
{
if constexpr(is_native_scheme(scheme))
{
*dst = static_cast<T>(0xD7C0 + (cdpt >> 10));
dst[1] = static_cast<T>(0xDC00 + (cdpt & 0x3FF));
}
else
{
*dst = byte_swap(static_cast<T>(0xD7C0 + (cdpt >> 10)));
dst[1] = byte_swap(static_cast<T>(0xDC00 + (cdpt & 0x3FF)));
}
return 2;
}
}
else
{
if (cdpt <= 0x7F)[[likely]]
{
*dst = static_cast<T>(cdpt);
return 1;
}
else if (cdpt <= 0x7FF)
{
*dst = static_cast<T>(0xC0 | ((cdpt >> 6) & 0x1F));
dst[1] = static_cast<T>(0x80 | (cdpt & 0x3F));
return 2;
}
else if (cdpt <= 0xFFFF)
{
*dst = static_cast<T>(0xE0 | ((cdpt >> 12) & 0x0F));
dst[1] = static_cast<T>(0x80 | ((cdpt >> 6) & 0x3F));
dst[2] = static_cast<T>(0x80 | (cdpt & 0x3F));
return 3;
}
else if (cdpt <= 0x10FFFF)
{
*dst = static_cast<T>(0xF0 | ((cdpt >> 18) & 0x07));
dst[1] = static_cast<T>(0x80 | ((cdpt >> 12) & 0x3F));
dst[2] = static_cast<T>(0x80 | ((cdpt >> 6) & 0x3F));
dst[3] = static_cast<T>(0x80 | (cdpt & 0x3F));
return 4;
}
else [[unlikely]]
return get_utf8_invalid_code_units(dst);
}
}
}
inline constexpr bool is_utf16_surrogate(char16_t uc) noexcept { return (uc - 0xd800u) < 2048u; }
inline constexpr bool is_utf16_high_surrogate(char16_t uc) noexcept { return (uc & 0xfffffc00) == 0xd800; }
inline constexpr bool is_utf16_low_surrogate(char16_t uc) noexcept { return (uc & 0xfffffc00) == 0xdc00; }
inline constexpr char32_t utf16_surrogate_to_utf32(char16_t high, char16_t low) noexcept
{
return static_cast<char32_t>((static_cast<std::uint_least32_t>(high) << 10u) + low - 0x35fdc00u);
}
#if (defined(_MSC_VER)&&defined(_M_AMD64)&&!defined(__clang__)) || (defined(__SSE__) && defined(__x86_64__))
template<std::integral T,std::integral U>
requires ((sizeof(T)==1)&&(sizeof(U)==1||sizeof(U)==2||sizeof(U)==4))
inline code_cvt_result<T,U> convert_ascii_with_sse(T const* __restrict pSrc, U* __restrict pDst) noexcept
{
std::uint_least32_t mask;
#if (defined(__GNUC__) || defined(__clang__)) && !defined(__INTEL_COMPILER)
using namespace fast_io::intrinsics;
constexpr std::size_t m128i_size{16};
if constexpr(sizeof(U)==1)
{
x86_64_v16qi chunk;
__builtin_memcpy(__builtin_addressof(chunk),pSrc,m128i_size);
mask = static_cast<std::uint_least32_t>(__builtin_ia32_pmovmskb128(chunk));
__builtin_memcpy(pDst,__builtin_addressof(chunk),m128i_size);
}
else if constexpr(sizeof(U)==2)
{
x86_64_v16qi const zero{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
x86_64_v16qi chunk;
__builtin_memcpy(__builtin_addressof(chunk),pSrc,m128i_size);
mask = static_cast<std::uint_least32_t>(__builtin_ia32_pmovmskb128(chunk));
#if __has_builtin(__builtin_shufflevector)
x86_64_v16qi half{__builtin_shufflevector(chunk, zero, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7)};
__builtin_memcpy(pDst,__builtin_addressof(half),m128i_size);
half = __builtin_shufflevector(chunk, zero, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
#else
x86_64_v16qi half{__builtin_ia32_punpcklbw128(chunk, zero)};
__builtin_memcpy(pDst,__builtin_addressof(half),m128i_size);
half = __builtin_ia32_punpckhbw128(chunk, zero);
#endif
__builtin_memcpy(pDst+8,__builtin_addressof(half),m128i_size);
}
else if constexpr(sizeof(U)==4)
{
x86_64_v16qi const zero{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
x86_64_v16qi chunk;
__builtin_memcpy(__builtin_addressof(chunk),pSrc,m128i_size);
mask = static_cast<std::uint_least32_t>(__builtin_ia32_pmovmskb128(chunk));
#if __has_builtin(__builtin_shufflevector)
x86_64_v16qi half_result{__builtin_shufflevector(chunk, zero, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7)};
x86_64_v8hi half;
__builtin_memcpy(__builtin_addressof(half),__builtin_addressof(half_result),m128i_size);
x86_64_v8hi const zero8{0, 0, 0, 0, 0, 0, 0, 0};
x86_64_v8hi qrtr{__builtin_shufflevector(half, zero8, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3)};
__builtin_memcpy(pDst,__builtin_addressof(qrtr),m128i_size);
qrtr = __builtin_shufflevector(half, zero8, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7);
__builtin_memcpy(pDst+4,__builtin_addressof(qrtr),m128i_size);
half_result = __builtin_shufflevector(chunk, zero, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
__builtin_memcpy(__builtin_addressof(half),__builtin_addressof(half_result),m128i_size);
qrtr=__builtin_shufflevector(half, zero8, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3);
__builtin_memcpy(pDst+8,__builtin_addressof(qrtr),m128i_size);
qrtr = __builtin_shufflevector(half, zero8, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7);
#else
x86_64_v16qi half_result{__builtin_ia32_punpcklbw128(chunk, zero)};
x86_64_v8hi half;
__builtin_memcpy(__builtin_addressof(half),__builtin_addressof(half_result),m128i_size);
x86_64_v8hi const zero8{0, 0, 0, 0, 0, 0, 0, 0};
x86_64_v8hi qrtr{__builtin_ia32_punpcklwd128(half, zero8)};
__builtin_memcpy(pDst,__builtin_addressof(qrtr),m128i_size);
qrtr = __builtin_ia32_punpckhwd128(half, zero8);
__builtin_memcpy(pDst+4,__builtin_addressof(qrtr),m128i_size);
half_result = __builtin_ia32_punpckhbw128(chunk, zero);
__builtin_memcpy(__builtin_addressof(half),__builtin_addressof(half_result),m128i_size);
qrtr=__builtin_ia32_punpcklwd128(half, zero8);
__builtin_memcpy(pDst+8,__builtin_addressof(qrtr),m128i_size);
qrtr = __builtin_ia32_punpckhwd128(half, zero8);
#endif
__builtin_memcpy(pDst+12,__builtin_addressof(qrtr),m128i_size);
}
#else
using x86_64_m128i = __m128i;
if constexpr(sizeof(U)==1)
{
x86_64_m128i chunk;
chunk = _mm_loadu_si128((x86_64_m128i const*) pSrc); //- Load the register with 8-bit bytes
mask = _mm_movemask_epi8(chunk); //- Determine which octets have high bit set
_mm_storeu_si128((x86_64_m128i*) pDst, chunk); //- Write to memory
}
else if constexpr(sizeof(U)==2)
{
x86_64_m128i chunk, half;
chunk = _mm_loadu_si128((x86_64_m128i const*) pSrc); //- Load the register with 8-bit bytes
mask = _mm_movemask_epi8(chunk); //- Determine which octets have high bit set
half = _mm_unpacklo_epi8(chunk, _mm_set1_epi8(0)); //- Unpack lower half into 16-bit words
_mm_storeu_si128((x86_64_m128i*) pDst, half); //- Write to memory
half = _mm_unpackhi_epi8(chunk, _mm_set1_epi8(0)); //- Unpack upper half into 16-bit words
_mm_storeu_si128((x86_64_m128i*) (pDst + 8), half); //- Write to memory
}
else
{
x86_64_m128i chunk, half, qrtr, zero;
zero = _mm_set1_epi8(0); //- Zero out the interleave register
chunk = _mm_loadu_si128((x86_64_m128i const*) pSrc); //- Load a register with 8-bit bytes
mask = _mm_movemask_epi8(chunk); //- Determine which octets have high bit set
half = _mm_unpacklo_epi8(chunk, zero); //- Unpack bytes 0-7 into 16-bit words
qrtr = _mm_unpacklo_epi16(half, zero); //- Unpack words 0-3 into 32-bit dwords
_mm_storeu_si128((x86_64_m128i*) pDst, qrtr); //- Write to memory
qrtr = _mm_unpackhi_epi16(half, zero); //- Unpack words 4-7 into 32-bit dwords
_mm_storeu_si128((x86_64_m128i*) (pDst + 4), qrtr); //- Write to memory
half = _mm_unpackhi_epi8(chunk, zero); //- Unpack bytes 8-15 into 16-bit words
qrtr = _mm_unpacklo_epi16(half, zero); //- Unpack words 8-11 into 32-bit dwords
_mm_storeu_si128((x86_64_m128i*) (pDst + 8), qrtr); //- Write to memory
qrtr = _mm_unpackhi_epi16(half, zero); //- Unpack words 12-15 into 32-bit dwords
_mm_storeu_si128((x86_64_m128i*) (pDst + 12), qrtr); //- Write to memory
}
#endif
auto const incr{std::countr_zero(static_cast<std::uint_least16_t>(mask))};
return {pSrc+incr,pDst+incr};
}
#endif
template<std::integral T>
struct advance_with_big_table_unchecked_result
{
T const* src;
char32_t cdpt;
};
template<std::integral T>
requires (sizeof(T)==1)
inline constexpr advance_with_big_table_unchecked_result<T> advance_with_big_table_unchecked(T const* it) noexcept
{
char8_t const* info{first_unit_info[static_cast<char8_t>(*it)]};
char32_t cdpt{static_cast<char32_t>(*info)}; //- From it, get the initial code point value
std::int_least32_t curr{info[1]}; //- From it, get the second state
for(++it;12<curr;)
{
char8_t const unit{static_cast<char8_t>(*it)};
++it; //- Cache the current code unit
cdpt = (cdpt << 6) | (unit & 0x3F); //- Adjust code point with continuation bits
curr = transitions[curr + octet_category[unit]];
//- Look up the next state
}
if(curr==12)[[unlikely]]
cdpt=0xFFFD;
return {it,cdpt};
}
template<std::integral T>
struct advance_with_big_table_result
{
bool failed;
T const* src;
char32_t cdpt;
};
template<std::integral T>
requires (sizeof(T)==1)
inline constexpr advance_with_big_table_result<T> advance_with_big_table(T const* first, T const* last) noexcept
{
char8_t const* info{first_unit_info[static_cast<char8_t>(*first)]};
char32_t cdpt{static_cast<char32_t>(*info)}; //- From it, get the initial code point value
std::int_least32_t curr{info[1]}; //- From it, get the second state
auto it{first};
for(++it;12<curr;)
{
if (it < last)[[likely]]
{
char8_t const unit{static_cast<char8_t>(*it)};
++it; //- Cache the current code unit
cdpt = (cdpt << 6) | (unit & 0x3F); //- Adjust code point with continuation bits
curr = transitions[curr + octet_category[unit]];
//- Look up the next state
}
else
return {true,nullptr,0};
}
if(curr==12)[[unlikely]]
cdpt=0xFFFD;
return {false,it,cdpt};
}
}
template<std::integral T>
requires (sizeof(T)<=4)
inline constexpr std::size_t get_utf_code_units(char32_t ch,T* ptr) noexcept
{
return details::codecvt::get_utf_code_units<encoding_scheme::utf>(ch,ptr);
}
}
@@ -0,0 +1,112 @@
#pragma once
namespace fast_io::details
{
/*
Referenced from UTF-EBCDIC
Unicode Technical Report #16
UTF-EBCDIC
EBCDIC-Friendly Unicode (or UCS) Transformation Format
1999-06-24
https://www.unicode.org/reports/tr16/tr16-5.html
*/
inline constexpr char8_t bm_i8_to_ebcdic[256]{0x0,0x1,0x2,0x3,0x37,0x2D,0x2E,0x2F,0x16,0x5,0x15,0xB,0xC,0xD,0xE,0xF,0x10,0x11,0x12,0x13,0x3C,0x3D,0x32,0x26,0x18,0x19,0x3F,0x27,0x1C,0x1D,0x1E,0x1F,0x40,0x5A,0x7F,0x7B,0x5B,0x6C,0x50,0x7D,0x4D,0x5D,0x5C,0x4E,0x6B,0x60,0x4B,0x61,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0x7A,0x5E,0x4C,0x7E,0x6E,0x6F,0x7C,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xAD,0xE0,0xBD,0x5F,0x6D,0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xC0,0x4F,0xD0,0xA1,0x7,0x20,0x21,0x22,0x23,0x24,0x25,0x6,0x17,0x28,0x29,0x2A,0x2B,0x2C,0x9,0xA,0x1B,0x30,0x31,0x1A,0x33,0x34,0x35,0x36,0x8,0x38,0x39,0x3A,0x3B,0x4,0x14,0x3E,0xFF,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x80,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xAA,0xAB,0xAC,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBF,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xFA,0xFB,0xFC,0xFD,0xFE};
inline constexpr char8_t bm_ebcdic_to_i8[256]{0x0,0x1,0x2,0x3,0x9C,0x9,0x86,0x7F,0x97,0x8D,0x8E,0xB,0xC,0xD,0xE,0xF,0x10,0x11,0x12,0x13,0x9D,0xA,0x8,0x87,0x18,0x19,0x92,0x8F,0x1C,0x1D,0x1E,0x1F,0x80,0x81,0x82,0x83,0x84,0x85,0x17,0x1B,0x88,0x89,0x8A,0x8B,0x8C,0x5,0x6,0x7,0x90,0x91,0x16,0x93,0x94,0x95,0x96,0x4,0x98,0x99,0x9A,0x9B,0x14,0x15,0x9E,0x1A,0x20,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0x2E,0x3C,0x28,0x2B,0x7C,0x26,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0x21,0x24,0x2A,0x29,0x3B,0x5E,0x2D,0x2F,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0x2C,0x25,0x5F,0x3E,0x3F,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0x60,0x3A,0x23,0x40,0x27,0x3D,0x22,0xC5,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0x7E,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0xD4,0xD5,0xD6,0x5B,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0x5D,0xE6,0xE7,0x7B,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0x7D,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0x5C,0xF4,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0xFB,0xFC,0xFD,0xFE,0xFF,0x9F};
inline constexpr char8_t utfebcdic_shadow_flags[256]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,9,9,9,9,9,9,9,9,9,9,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,1,1,1,1,1,9,9,9,9,2,2,2,2,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,2,2,2,1,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,1,3,3,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,3,3,4,4,4,4,1,4,1,1,1,1,1,1,1,1,4,4,4,5,5,5,1,1,1,1,1,1,1,1,1,1,5,6,6,7,7,0};
template<std::integral T>
requires (sizeof(T)==1)
inline constexpr std::size_t get_utf_ebcdic_invalid_code_units(T* dst) noexcept
{
*dst=0xDD;
dst[1]=0x73;
dst[2]=0x66;
dst[3]=0x73;
return 4;
}
template<std::integral T>
requires (sizeof(T)==1)
inline constexpr std::size_t get_utf_ebcdic_code_units(char32_t code,T* dst) noexcept
{
if(code<0xA0)
{
*dst=static_cast<T>(bm_i8_to_ebcdic[code]);
return 1;
}
else if(code<0x400)
{
*dst=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b11000000)|(code>>5)]);
dst[1]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|(code&static_cast<char32_t>(0b11111))]);
return 2;
}
else if(code<0x4000)
{
*dst=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b11100000)|(code>>10)]);
dst[1]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|((code>>5)&static_cast<char32_t>(0b11111))]);
dst[2]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|(code&static_cast<char32_t>(0b11111))]);
return 3;
}
else if(code<0x40000)
{
*dst=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b11110000)|(code>>15)]);
dst[1]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|((code>>10)&static_cast<char32_t>(0b11111))]);
dst[2]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|((code>>5)&static_cast<char32_t>(0b11111))]);
dst[3]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|(code&static_cast<char32_t>(0b11111))]);
return 4;
}
else if(code<0x110000)
{
*dst=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b11111000)|(code>>20)]);
dst[1]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|((code>>15)&static_cast<char32_t>(0b11111))]);
dst[2]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|((code>>10)&static_cast<char32_t>(0b11111))]);
dst[3]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|((code>>5)&static_cast<char32_t>(0b11111))]);
dst[4]=static_cast<T>(bm_i8_to_ebcdic[static_cast<char32_t>(0b10100000)|(code&static_cast<char32_t>(0b11111))]);
return 5;
}
return get_utf_ebcdic_invalid_code_units(dst);
}
struct from_ebcdic_result
{
char32_t code;
char8_t len;
};
template<std::integral T>
requires (sizeof(T)==1)
inline constexpr from_ebcdic_result utf_ebcdic_advance(T* src_first,std::size_t sz) noexcept
{
char8_t src0(static_cast<char8_t>(*src_first));
char8_t shadow{utfebcdic_shadow_flags[src0]};
if(shadow<2)
return {static_cast<char32_t>(bm_ebcdic_to_i8[src0]),1};
if(shadow==9)
return {0xFFFD,1};
if(sz<shadow)
return {0,static_cast<char8_t>(-1)};
char32_t res{};
for(char8_t i{1};i!=shadow;++i)
{
char8_t code(bm_ebcdic_to_i8[static_cast<char8_t>(src_first[i])]);
if((code>>5)!=0b101)[[unlikely]]
return {0xFFFD,i};
res=(res<<5)|(code&0b11111);
}
char8_t src0i18{bm_ebcdic_to_i8[src0]};
switch(shadow)
{
case 2:
return {((static_cast<char32_t>(src0i18&0b11111))<<5)|res,2};
case 3:
return {((static_cast<char32_t>(src0i18&0b1111))<<10)|res,3};
case 4:
return {((static_cast<char32_t>(src0i18&0b111))<<15)|res,4};
case 5:
return {((static_cast<char32_t>(src0i18&0b1))<<20)|res,5};
default:
return {0xFFFD,shadow};
};
}
}
@@ -0,0 +1,10 @@
#pragma once
namespace fast_io::details::codecvt
{
inline constexpr char8_t first_unit_info[256][2]{{0,0},{1,0},{2,0},{3,0},{4,0},{5,0},{6,0},{7,0},{8,0},{9,0},{10,0},{11,0},{12,0},{13,0},{14,0},{15,0},{16,0},{17,0},{18,0},{19,0},{20,0},{21,0},{22,0},{23,0},{24,0},{25,0},{26,0},{27,0},{28,0},{29,0},{30,0},{31,0},{32,0},{33,0},{34,0},{35,0},{36,0},{37,0},{38,0},{39,0},{40,0},{41,0},{42,0},{43,0},{44,0},{45,0},{46,0},{47,0},{48,0},{49,0},{50,0},{51,0},{52,0},{53,0},{54,0},{55,0},{56,0},{57,0},{58,0},{59,0},{60,0},{61,0},{62,0},{63,0},{64,0},{65,0},{66,0},{67,0},{68,0},{69,0},{70,0},{71,0},{72,0},{73,0},{74,0},{75,0},{76,0},{77,0},{78,0},{79,0},{80,0},{81,0},{82,0},{83,0},{84,0},{85,0},{86,0},{87,0},{88,0},{89,0},{90,0},{91,0},{92,0},{93,0},{94,0},{95,0},{96,0},{97,0},{98,0},{99,0},{100,0},{101,0},{102,0},{103,0},{104,0},{105,0},{106,0},{107,0},{108,0},{109,0},{110,0},{111,0},{112,0},{113,0},{114,0},{115,0},{116,0},{117,0},{118,0},{119,0},{120,0},{121,0},{122,0},{123,0},{124,0},{125,0},{126,0},{127,0},{0,12},{1,12},{2,12},{3,12},{4,12},{5,12},{6,12},{7,12},{8,12},{9,12},{10,12},{11,12},{12,12},{13,12},{14,12},{15,12},{16,12},{17,12},{18,12},{19,12},{20,12},{21,12},{22,12},{23,12},{24,12},{25,12},{26,12},{27,12},{28,12},{29,12},{30,12},{31,12},{32,12},{33,12},{34,12},{35,12},{36,12},{37,12},{38,12},{39,12},{40,12},{41,12},{42,12},{43,12},{44,12},{45,12},{46,12},{47,12},{48,12},{49,12},{50,12},{51,12},{52,12},{53,12},{54,12},{55,12},{56,12},{57,12},{58,12},{59,12},{60,12},{61,12},{62,12},{63,12},{192,12},{193,12},{2,24},{3,24},{4,24},{5,24},{6,24},{7,24},{8,24},{9,24},{10,24},{11,24},{12,24},{13,24},{14,24},{15,24},{16,24},{17,24},{18,24},{19,24},{20,24},{21,24},{22,24},{23,24},{24,24},{25,24},{26,24},{27,24},{28,24},{29,24},{30,24},{31,24},{0,60},{1,36},{2,36},{3,36},{4,36},{5,36},{6,36},{7,36},{8,36},{9,36},{10,36},{11,36},{12,36},{13,72},{14,36},{15,36},{0,84},{1,48},{2,48},{3,48},{4,96},{245,12},{246,12},{247,12},{248,12},{249,12},{250,12},{251,12},{252,12},{253,12},{254,12},{255,12}};
inline constexpr char8_t octet_category[256]{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,7,7,7,7,7,7,7,7,7,7,7,7,8,7,7,9,10,10,10,11,0,0,0,0,0,0,0,0,0,0,0};
inline constexpr char8_t transitions[108]{12,0,12,12,12,24,60,36,72,84,48,96,12,12,12,12,12,12,12,12,12,12,12,12,12,12,0,0,0,12,12,12,12,12,12,12,12,12,24,24,24,12,12,12,12,12,12,12,12,12,36,36,36,12,12,12,12,12,12,12,12,12,12,12,24,12,12,12,12,12,12,12,12,12,24,24,12,12,12,12,12,12,12,12,12,12,12,36,36,12,12,12,12,12,12,12,12,12,36,12,12,12,12,12,12,12,12,12};
}
@@ -0,0 +1,51 @@
#pragma once
namespace fast_io
{
template<std::integral char_type,typename T>
requires (std::same_as<T,std::weak_ordering>||std::same_as<T,std::strong_ordering>||
std::same_as<T,std::partial_ordering>)
inline constexpr std::size_t print_reserve_size(io_reserve_type_t<char_type,T>) noexcept
{
return 1;
}
template<::std::integral char_type,typename T>
requires (std::same_as<T,std::weak_ordering>||std::same_as<T,std::strong_ordering>||
std::same_as<T,std::partial_ordering>)
inline constexpr char_type* print_reserve_define(io_reserve_type_t<char_type,T>, char_type* iter,T t) noexcept
{
if(t<0)
{
if constexpr(std::same_as<char_type,char>)
*iter='<';
else if constexpr(std::same_as<char_type,wchar_t>)
*iter=L'<';
else
*iter=u8'<';
}
else if(t==0)
{
if constexpr(std::same_as<char_type,char>)
*iter='=';
else if constexpr(std::same_as<char_type,wchar_t>)
*iter=L'=';
else
*iter=u8'=';
}
else
{
if constexpr(std::same_as<char_type,char>)
*iter='>';
else if constexpr(std::same_as<char_type,wchar_t>)
*iter=L'>';
else
*iter=u8'>';
}
++iter;
return iter;
}
}
@@ -0,0 +1,102 @@
#pragma once
namespace fast_io::details
{
template<std::integral ch_type>
struct basic_concat_buffer
{
using char_type = ch_type;
static inline constexpr std::size_t buffer_size{2048u/sizeof(ch_type)};
char_type *buffer_begin,*buffer_curr,*buffer_end;
char_type stack_buffer[buffer_size];
constexpr basic_concat_buffer() noexcept:
buffer_begin{stack_buffer},
buffer_curr{stack_buffer},
buffer_end{stack_buffer+buffer_size}
{}
basic_concat_buffer(basic_concat_buffer const&)=delete;
basic_concat_buffer& operator=(basic_concat_buffer const&)=delete;
#if __cpp_constexpr_dynamic_alloc >= 201907L
constexpr
#endif
~basic_concat_buffer()
{
if(buffer_begin!=stack_buffer)[[unlikely]]
{
deallocate_iobuf_space<false,ch_type>(buffer_begin,static_cast<std::size_t>(buffer_end-buffer_begin));
}
}
};
template<std::integral char_type>
inline constexpr char_type* strlike_begin(::fast_io::io_strlike_type_t<char_type,::fast_io::details::basic_concat_buffer<char_type>>,::fast_io::details::basic_concat_buffer<char_type>& str) noexcept
{
return str.buffer_begin;
}
template<std::integral char_type>
inline constexpr char_type* strlike_curr(::fast_io::io_strlike_type_t<char_type,::fast_io::details::basic_concat_buffer<char_type>>,::fast_io::details::basic_concat_buffer<char_type>& str) noexcept
{
return str.buffer_curr;
}
template<std::integral char_type>
inline constexpr char_type* strlike_end(::fast_io::io_strlike_type_t<char_type,::fast_io::details::basic_concat_buffer<char_type>>,::fast_io::details::basic_concat_buffer<char_type>& str) noexcept
{
return str.buffer_end;
}
template<std::integral char_type>
inline constexpr void strlike_set_curr(::fast_io::io_strlike_type_t<char_type,::fast_io::details::basic_concat_buffer<char_type>>,::fast_io::details::basic_concat_buffer<char_type>& str,char_type* p) noexcept
{
str.buffer_curr=p;
}
template<std::integral char_type>
#if __has_cpp_attribute(__gnu__::__cold__)
[[__gnu__::__cold__]]
#endif
inline constexpr void basic_concat_buffer_strlike_reserve_cold_impl(::fast_io::details::basic_concat_buffer<char_type>& str,std::size_t n,std::size_t df) noexcept
{
auto old_buffer_begin_ptr{str.buffer_begin};
bool onstack{old_buffer_begin_ptr==str.stack_buffer};
auto newptr{allocate_iobuf_space<char_type>(n)};
std::size_t const elements{static_cast<std::size_t>(str.buffer_curr-str.buffer_begin)};
auto newcurr_ptr{non_overlapped_copy_n(old_buffer_begin_ptr,elements,newptr)};
str.buffer_curr=newcurr_ptr;
if(!onstack)
{
deallocate_iobuf_space<false,char_type>(old_buffer_begin_ptr,df);
}
str.buffer_begin=newptr;
str.buffer_end=newptr+n;
}
template<std::integral char_type>
inline constexpr void basic_concat_buffer_strlike_reserve_impl(::fast_io::details::basic_concat_buffer<char_type>& str,std::size_t n) noexcept
{
std::size_t df{static_cast<std::size_t>(str.buffer_end-str.buffer_begin)};
if(df<n)[[unlikely]]
basic_concat_buffer_strlike_reserve_cold_impl(str,n,df);
}
template<std::integral char_type>
inline constexpr void strlike_reserve(::fast_io::io_strlike_type_t<char_type,::fast_io::details::basic_concat_buffer<char_type>>,::fast_io::details::basic_concat_buffer<char_type>& str,std::size_t n) noexcept
{
basic_concat_buffer_strlike_reserve_impl(str,n);
}
template<std::integral char_type>
inline constexpr std::size_t strlike_sso_size(::fast_io::io_strlike_type_t<char_type,::fast_io::details::basic_concat_buffer<char_type>>) noexcept
{
return ::fast_io::details::basic_concat_buffer<char_type>::buffer_size;
}
template<std::integral char_type>
inline constexpr io_strlike_reference_wrapper<char_type,::fast_io::details::basic_concat_buffer<char_type>> io_strlike_ref(io_alias_t,::fast_io::details::basic_concat_buffer<char_type>& str) noexcept
{
return {__builtin_addressof(str)};
}
}
@@ -0,0 +1,312 @@
#pragma once
namespace fast_io::details::decay
{
template<bool line,::std::integral char_type,typename T,typename... Args>
inline constexpr char_type* print_reserve_define_chain_impl(char_type* p,T t,Args ...args)
{
if constexpr(sizeof...(Args)==0)
{
p=print_reserve_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,p,t);
if constexpr(line)
{
*p=char_literal_v<u8'\n',char_type>;
++p;
}
return p;
}
else
return print_reserve_define_chain_impl<line>(print_reserve_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,p,t),args...);
}
template<std::integral char_type,typename T,typename... Args>
inline constexpr std::size_t calculate_scatter_dynamic_reserve_size_with_scatter([[maybe_unused]] T t,Args... args)
{
if constexpr(dynamic_reserve_printable<char_type,T>)
{
std::size_t res{print_reserve_size(io_reserve_type<char_type,T>,t)};
if constexpr(sizeof...(Args)==0)
return res;
else
return ::fast_io::details::intrinsics::add_or_overflow_die(res,calculate_scatter_dynamic_reserve_size_with_scatter<char_type>(args...));
}
else if constexpr(scatter_printable<char_type,T>)
{
std::size_t res{print_scatter_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,t).len};
if constexpr(sizeof...(Args)==0)
return res;
else
return ::fast_io::details::intrinsics::add_or_overflow_die(res,calculate_scatter_dynamic_reserve_size_with_scatter<char_type>(args...));
}
else
{
if constexpr(sizeof...(Args)==0)
return 0;
else
return calculate_scatter_dynamic_reserve_size_with_scatter<char_type>(args...);
}
}
template<bool line,::std::integral char_type,typename T,typename... Args>
inline constexpr char_type* print_reserve_define_chain_scatter_impl(char_type* p,T t,Args ...args)
{
if constexpr(dynamic_reserve_printable<char_type,T>||reserve_printable<char_type,T>)
p = print_reserve_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,p,t);
else
{
auto sc{print_scatter_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,t)};
p = non_overlapped_copy_n(sc.base,sc.len,p);
}
if constexpr(sizeof...(Args)==0)
{
if constexpr(line)
{
*p=char_literal_v<u8'\n',char_type>;
++p;
}
return p;
}
else
return print_reserve_define_chain_scatter_impl<line>(p,args...);
}
template<std::integral ch_type,typename T>
inline constexpr basic_io_scatter_t<ch_type> print_scatter_define_extract_one(T t)
{
return print_scatter_define(io_reserve_type<ch_type,std::remove_cvref_t<T>>,t);
}
template<bool line,std::integral ch_type,typename T,typename Arg>
inline constexpr T basic_general_concat_decay_impl_precise(T& str,Arg arg)
{
std::size_t precise_size{print_reserve_precise_size(io_reserve_type<ch_type,Arg>,arg)};
std::size_t precise_size_with_line{precise_size};
if constexpr(line)
++precise_size_with_line;
constexpr std::size_t local_cap{strlike_sso_size(io_strlike_type<ch_type,T>)};
if(local_cap<precise_size_with_line)
strlike_reserve(io_strlike_type<ch_type,T>,str,local_cap);
auto first{strlike_begin(io_strlike_type<ch_type,T>,str)};
print_reserve_precise_define(io_reserve_type<ch_type,Arg>,first,precise_size,arg);
auto ptr{first+precise_size};
if constexpr(line)
{
*ptr=char_literal_v<u8'\n',ch_type>;
++ptr;
}
strlike_set_curr(io_strlike_type<ch_type,T>,str,ptr);
return str;
}
template<bool line,std::integral ch_type,typename T,typename... Args>
inline constexpr T basic_general_concat_decay_impl(Args ...args)
{
if constexpr(sizeof...(Args)==0)
{
if constexpr(line)
{
return strlike_construct_single_character_define(io_strlike_type<ch_type,T>,char_literal_v<u8'\n',ch_type>);
}
else
{
return {};
}
}
else if constexpr(((reserve_printable<ch_type,Args>||scatter_printable<ch_type,Args>||dynamic_reserve_printable<ch_type,Args>)&&...))
{
constexpr std::size_t sz{calculate_scatter_reserve_size<ch_type,Args...>()};
if constexpr(line)
static_assert(sz!=SIZE_MAX,"overflow\n");
constexpr std::size_t sz_with_line{sz+static_cast<std::size_t>(line)};
if constexpr((reserve_printable<ch_type,Args>&&...))
{
if constexpr(sso_buffer_strlike<ch_type,T>)
{
constexpr std::size_t local_cap{strlike_sso_size(io_reserve_type<ch_type,T>)};
constexpr bool not_enough_space{(local_cap<sz_with_line)};
if constexpr(not_enough_space && ((sizeof...(Args)==1)&&(precise_reserve_printable<ch_type,Args>&&...)))
{
return basic_general_concat_decay_impl_precise<line,ch_type,T>(args...);
}
else
{
T str;
if constexpr(not_enough_space)
strlike_reserve(io_strlike_type<ch_type,T>,str,sz_with_line);
strlike_set_curr(io_strlike_type<ch_type,T>,str,
print_reserve_define_chain_impl<line>(strlike_begin(io_strlike_type<ch_type,T>,str),args...));
return str;
}
}
else
{
T str;
strlike_reserve(io_strlike_type<ch_type,T>,str,sz_with_line);
strlike_set_curr(io_strlike_type<ch_type,T>,str,
print_reserve_define_chain_impl<line>(strlike_begin(io_strlike_type<ch_type,T>,str),args...));
return str;
}
}
else
{
if constexpr((!line)&&sizeof...(args)==1&&(scatter_printable<ch_type,Args>&&...))
{
basic_io_scatter_t<ch_type> scatter{print_scatter_define_extract_one<ch_type>(args...)};
return strlike_construct_define(io_strlike_type<ch_type,T>(scatter.base,scatter.base+scatter.len));
}
else
{
std::size_t total_size{::fast_io::details::intrinsics::add_or_overflow_die(sz_with_line,calculate_scatter_dynamic_reserve_size_with_scatter<ch_type>(args...))};
T str;
strlike_reserve(io_strlike_type<ch_type,T>,str,total_size);
strlike_set_curr(io_strlike_type<ch_type,T>,str,
print_reserve_define_chain_scatter_impl<line>(strlike_begin(io_strlike_type<ch_type,T>,str),args...));
return str;
}
}
}
else
{
T str;
auto oref{io_strlike_ref(fast_io::io_alias,str)};
::fast_io::print_freestanding_decay_no_status<line>(oref,args...);
return str;
}
}
template<bool line,std::integral ch_type,typename T,typename Arg>
inline constexpr void basic_general_concat_decay_ref_impl_precise(T& str,Arg arg)
{
std::size_t precise_size{print_reserve_precise_size(io_reserve_type<ch_type,Arg>,arg)};
std::size_t precise_size_with_line{precise_size};
if constexpr(line)
++precise_size_with_line;
constexpr std::size_t local_cap{strlike_sso_size(io_strlike_type<ch_type,T>)};
if(local_cap<precise_size_with_line)
strlike_reserve(io_strlike_type<ch_type,T>,str,precise_size_with_line);
auto first{strlike_begin(io_strlike_type<ch_type,T>,str)};
print_reserve_precise_define(io_reserve_type<ch_type,Arg>,first,precise_size,arg);
auto ptr{first+precise_size};
if constexpr(line)
{
*ptr=char_literal_v<u8'\n',ch_type>;
++ptr;
}
strlike_set_curr(io_strlike_type<ch_type,T>,str,ptr);
}
template<bool line,std::integral ch_type,typename T,typename... Args>
inline constexpr void basic_general_concat_decay_ref_impl(T& str,Args ...args)
{
if constexpr(((reserve_printable<ch_type,Args>||scatter_printable<ch_type,Args>||dynamic_reserve_printable<ch_type,Args>)&&...))
{
constexpr std::size_t sz{calculate_scatter_reserve_size<ch_type,Args...>()};
if constexpr(line)
static_assert(sz!=SIZE_MAX,"overflow\n");
constexpr std::size_t sz_with_line{sz+static_cast<std::size_t>(line)};
if constexpr((reserve_printable<ch_type,Args>&&...))
{
if constexpr(sso_buffer_strlike<ch_type,T>)
{
constexpr std::size_t local_cap{strlike_sso_size(io_strlike_type<ch_type,T>)};
constexpr bool not_enough_space{(local_cap<sz_with_line)};
if constexpr(not_enough_space && ((sizeof...(Args)==1)&&(precise_reserve_printable<ch_type,Args>&&...)))
{
basic_general_concat_decay_ref_impl_precise<line,ch_type,T>(str,args...);
}
else
{
if constexpr(not_enough_space)
strlike_reserve(io_strlike_type<ch_type,T>,str,sz_with_line);
strlike_set_curr(io_strlike_type<ch_type,T>,str,
print_reserve_define_chain_impl<line>(strlike_begin(io_strlike_type<ch_type,T>,str),args...));
}
}
else
{
strlike_reserve(io_strlike_type<ch_type,T>,str,sz_with_line);
strlike_set_curr(io_strlike_type<ch_type,T>,str,
print_reserve_define_chain_impl<line>(strlike_begin(io_strlike_type<ch_type,T>,str),args...));
}
}
else
{
std::size_t total_size{::fast_io::details::intrinsics::add_or_overflow_die(sz_with_line,calculate_scatter_dynamic_reserve_size_with_scatter<ch_type>(args...))};
strlike_reserve(io_strlike_type<ch_type,T>,str,total_size);
strlike_set_curr(io_strlike_type<ch_type,T>,str,
print_reserve_define_chain_scatter_impl<line>(strlike_begin(io_strlike_type<ch_type,T>,str),args...));
}
}
else
{
auto oref{io_strlike_ref(fast_io::io_alias,str)};
::fast_io::print_freestanding_decay_no_status<line>(oref,args...);
}
}
template<bool line,std::integral ch_type,typename T,typename... Args>
inline constexpr T basic_general_concat_phase1_decay_impl(Args ...args)
{
if constexpr(sizeof...(Args)==0)
{
if constexpr(line)
{
if constexpr(single_character_constructible_strlike<ch_type,T>)
return strlike_construct_single_character_define(io_strlike_type<ch_type,T>,char_literal_v<u8'\n',ch_type>);
else
{
return strlike_construct_define(io_strlike_type<ch_type,T>,__builtin_addressof(char_literal_v<u8'\n',ch_type>),__builtin_addressof(char_literal_v<u8'\n',ch_type>)+1);
}
}
else
{
return {};
}
}
else
{
if constexpr(buffer_strlike<ch_type,T>)
{
T str;
basic_general_concat_decay_ref_impl<line,ch_type>(str,args...);
return str;
}
else if constexpr((!line)&&sizeof...(args)==1&&(scatter_printable<ch_type,Args>&&...))
{
basic_io_scatter_t<ch_type> scatter{print_scatter_define_extract_one<ch_type>(args...)};
return strlike_construct_define(io_strlike_type<ch_type,T>,scatter.base,scatter.base+scatter.len);
}
else if constexpr((reserve_printable<ch_type,Args>&&...))
{
constexpr std::size_t sz{calculate_scatter_reserve_size<ch_type,Args...>()};
if constexpr(line)
static_assert(sz!=SIZE_MAX,"overflow\n");
constexpr std::size_t sz_with_line{sz+static_cast<std::size_t>(line)};
ch_type buffer[sz_with_line];
auto p{print_reserve_define_chain_impl<line>(buffer,args...)};
return strlike_construct_define(io_strlike_type<ch_type,T>,buffer,p);
}
else
{
basic_concat_buffer<ch_type> buffer;
basic_general_concat_decay_ref_impl<line,ch_type>(buffer,args...);
return strlike_construct_define(io_strlike_type<ch_type,T>,buffer.buffer_begin,buffer.buffer_curr);
}
}
}
}
namespace fast_io
{
template<bool line,std::integral char_type,typename T,typename ...Args>
requires strlike<char_type,T>
inline constexpr T basic_general_concat(Args&& ...args)
{
return ::fast_io::details::decay::basic_general_concat_phase1_decay_impl<line,char_type,T>(
io_print_forward<char_type>(io_print_alias(args))...);
}
}
@@ -0,0 +1,4 @@
#pragma once
#include"strlike_reference_wrapper.h"
#include"concat_buffer.h"
#include"concat_general.h"
@@ -0,0 +1,189 @@
#pragma once
namespace fast_io
{
template<std::integral ch_type,typename T>
struct io_strlike_reference_wrapper
{
using value_type = T;
using native_handle_type = value_type*;
using char_type = ch_type;
using pointer = char_type*;
using const_pointer = char_type const*;
native_handle_type ptr{};
inline constexpr native_handle_type release() noexcept
{
auto temp{ptr};
ptr=nullptr;
return temp;
}
inline constexpr native_handle_type native_handle() const noexcept
{
return ptr;
}
};
template<std::integral char_type,typename T>
[[nodiscard]] inline constexpr io_strlike_reference_wrapper<char_type,T> io_value_handle(io_strlike_reference_wrapper<char_type,T> bref) noexcept
{
return bref;
}
template<std::integral char_type,typename T>
requires buffer_strlike<char_type,T>
inline constexpr char_type* obuffer_begin(io_strlike_reference_wrapper<char_type,T> bref) noexcept
{
return strlike_begin(io_strlike_type<char_type,T>,*bref.ptr);
}
template<std::integral char_type,typename T>
requires buffer_strlike<char_type,T>
inline constexpr char_type* obuffer_curr(io_strlike_reference_wrapper<char_type,T> bref) noexcept
{
return strlike_curr(io_strlike_type<char_type,T>,*bref.ptr);
}
template<std::integral char_type,typename T>
requires buffer_strlike<char_type,T>
inline constexpr char_type* obuffer_end(io_strlike_reference_wrapper<char_type,T> bref) noexcept
{
return strlike_end(io_strlike_type<char_type,T>,*bref.ptr);
}
template<std::integral char_type,typename T>
requires buffer_strlike<char_type,T>
inline constexpr void obuffer_set_curr(io_strlike_reference_wrapper<char_type,T> bref,char_type* i) noexcept
{
return strlike_set_curr(io_strlike_type<char_type,T>,*bref.ptr,i);
}
namespace details
{
template<std::size_t size_char_type>
inline constexpr std::size_t cal_new_cap_io_strlike(std::size_t cap) noexcept
{
std::size_t new_cap{};
if(cap==0)
new_cap=1;
else
{
constexpr std::size_t mx_size{SIZE_MAX/size_char_type};
constexpr std::size_t mx_div2{static_cast<std::size_t>(mx_size/2u)};
if(mx_size==cap)[[unlikely]]
{
fast_terminate();
}
else if(cap>=mx_div2)
{
new_cap=mx_size;
}
else
{
new_cap=cap;
new_cap<<=1u;
}
}
return new_cap;
}
}
template<std::integral ch_type,typename T>
requires buffer_strlike<ch_type,T>
#if __has_cpp_attribute(__gnu__::__cold__)
[[__gnu__::__cold__]]
#endif
inline constexpr void obuffer_overflow(io_strlike_reference_wrapper<ch_type,T> bref,ch_type ch)
{
auto& strref{*bref.ptr};
if constexpr(auxiliary_strlike<ch_type,T>)
{
strlike_push_back(io_strlike_type<ch_type,T>,strref,ch);
}
else
{
auto bptr{strlike_begin(io_strlike_type<ch_type,T>,strref)};
auto eptr{strlike_end(io_strlike_type<ch_type,T>,strref)};
auto cap{static_cast<std::size_t>(eptr-bptr)};
strlike_reserve(io_strlike_type<ch_type,T>,strref,::fast_io::details::cal_new_cap_io_strlike<sizeof(ch_type)>(cap));
auto curr_ptr{strlike_curr(io_strlike_type<ch_type,T>,strref)};
*curr_ptr=ch;
++curr_ptr;
strlike_set_curr(io_strlike_type<ch_type,T>,strref,curr_ptr);
}
}
namespace details
{
template<std::integral ch_type,typename T>
#if __has_cpp_attribute(__gnu__::__cold__)
[[__gnu__::__cold__]]
#endif
inline constexpr void write_strike_like_cold(io_strlike_reference_wrapper<ch_type,T> bref,ch_type const* first,ch_type const* last)
{
auto& strref{*bref.ptr};
auto curr{strlike_curr(io_strlike_type<ch_type,T>,strref)};
std::size_t const bufferdiff{static_cast<std::size_t>(strlike_end(io_strlike_type<ch_type,T>,strref)-curr)};
curr=non_overlapped_copy_n(first,bufferdiff,curr);
first+=bufferdiff;
strlike_set_curr(io_strlike_type<ch_type,T>,strref,curr);
auto bptr{strlike_begin(io_strlike_type<ch_type,T>,strref)};
auto eptr{strlike_end(io_strlike_type<ch_type,T>,strref)};
auto cap{static_cast<std::size_t>(eptr-bptr)};
std::size_t new_cap{::fast_io::details::cal_new_cap_io_strlike<sizeof(ch_type)>(cap)};
std::size_t const size_minimum{::fast_io::details::intrinsics::add_or_overflow_die(static_cast<std::size_t>(last-first),cap)};
if(new_cap<size_minimum)
new_cap=size_minimum;
strlike_reserve(io_strlike_type<ch_type,T>,strref,new_cap);
auto curr_ptr{strlike_curr(io_strlike_type<ch_type,T>,strref)};
curr_ptr=non_overlapped_copy(first,last,curr_ptr);
strlike_set_curr(io_strlike_type<ch_type,T>,strref,curr_ptr);
}
}
template<std::integral ch_type,typename T, ::std::contiguous_iterator Iter>
requires (std::same_as<ch_type,char>||std::same_as<ch_type, ::std::iter_value_t<Iter>>)
inline constexpr void write(io_strlike_reference_wrapper<ch_type,T> bref,Iter first,Iter last)
{
if constexpr(std::same_as<::std::iter_value_t<Iter>,ch_type>)
{
if constexpr(std::is_pointer_v<Iter>)
{
auto& strref{*bref.ptr};
if constexpr(auxiliary_strlike<ch_type,T>)
{
strlike_append(io_strlike_type<ch_type,T>,strref,first,last);
}
else
{
std::size_t const iterdiff{static_cast<std::size_t>(last-first)};
ch_type* curr{strlike_curr(io_strlike_type<ch_type,T>,strref)};
std::size_t const bufferdiff{static_cast<std::size_t>(strlike_end(io_strlike_type<ch_type,T>,strref)-curr)};
if(iterdiff<=bufferdiff)[[likely]]
{
::fast_io::details::non_overlapped_copy_n(first,iterdiff,curr);
strlike_set_curr(io_strlike_type<ch_type,T>,strref,curr+iterdiff);
}
else[[unlikely]]
{
::fast_io::details::write_strike_like_cold(bref,first,last);
}
}
}
else
{
write(bref,::std::to_address(first),::std::to_address(last));
}
}
else
{
write(bref,reinterpret_cast<char const*>(::std::to_address(first)),
reinterpret_cast<char const*>(::std::to_address(last)));
}
}
}
@@ -0,0 +1,50 @@
#pragma once
namespace fast_io
{
#if 0
template<typename to_value_type,typename T>
concept decorator=requires(T t,to_value_type* dest,std::size_t size)
{
{deco_reserve_size(io_reserve_type<to_value_type,T>,t,size)}->std::same_as<std::size_t>;
};
template<typename from_value_type,typename to_value_type,typename T>
concept decoratable = decorator<to_value_type,T>&&requires(T t,from_value_type const* ptr,to_value_type* dest)
{
{deco_reserve_define(io_reserve_type<to_value_type,T>,t,ptr,ptr,dest)}->std::convertible_to<to_value_type*>;
};
template<typename to_value_type,typename T>
concept maybe_noop_decorator=decorator<to_value_type,T>&&requires(T t)
{
{deco_maybe_noop(io_reserve_type<to_value_type,T>,t)}->std::convertible_to<bool>;
};
template<typename to_value_type,typename T>
concept always_noop_decorator=decorator<to_value_type,T>&&requires()
{
deco_always_noop(io_reserve_type<to_value_type,T>);//must be consteval
};
template<typename to_value_type,typename T>
concept reserve_inverse_size_decorator=decorator<to_value_type,T>&&requires(T t,std::size_t size)
{
{deco_reserve_inverse_size(io_reserve_type<to_value_type,T>,t,size)}->std::same_as<std::size_t>;
};
#endif
template<typename T>
concept value_based_decorator = requires(T t)
{
{deco_value_handle(t)};
};
#if 0
template<typename to_value_type,typename T>
concept unshift_decorator = decorator<to_value_type,T>&&requires(T t,to_value_type const* from_iter,to_value_type const* to_iter)
{
{deco_unshift_size(io_reserve_type<to_value_type,T>,t)};
{deco_unshift_define(io_reserve_type<to_value_type,T>,t,from_iter,to_iter)};
};
#endif
}
@@ -0,0 +1,258 @@
#pragma once
namespace fast_io::details
{
template<typename T>
concept stream_char_type_requirement = requires()
{
typename std::remove_cvref_t<T>::char_type;
};
template<typename T>
concept input_stream_impl =
(stream_char_type_requirement<T>||
(requires()
{
typename std::remove_cvref_t<T>::input_char_type;
})
)&&requires(T&& in,typename std::remove_cvref_t<T>::char_type* b)
{
read(in,b,b);
};
template<typename T>
concept output_stream_impl = (stream_char_type_requirement<T>||
(requires()
{
typename std::remove_cvref_t<T>::output_char_type;
})
)&&requires(T&& out,typename std::remove_cvref_t<T>::char_type const* b)
{
write(out,b,b);
};
template<typename T>
concept mutex_stream_impl = requires(T&& t)
{
t.lock();
t.unlock();
t.unlocked_handle();
};
template<typename T>
concept random_access_stream_impl = requires(T&& t)
{
seek(t,5);
};
template<typename T>
concept buffer_input_stream_impl = requires(T&& in)
{
ibuffer_begin(in);
ibuffer_set_curr(in,ibuffer_curr(in));
ibuffer_end(in);
{ibuffer_underflow(in)}->std::convertible_to<bool>;
};
template<typename T>
concept contiguous_input_stream_impl = requires(T&& in)
{
ibuffer_underflow_never(in);
};
template<typename T>
concept contiguous_output_stream_impl = requires(T&& out)
{
obuffer_overflow_never(out);
};
template<typename T>
concept refill_buffer_input_stream_impl = requires(T&& in)
{
{irefill(in)}->std::convertible_to<bool>;
};
template<typename T>
concept buffer_output_stream_impl = requires(T&& out,typename std::remove_cvref_t<T>::char_type ch)
{
obuffer_begin(out);
obuffer_end(out);
obuffer_set_curr(out,obuffer_curr(out));
obuffer_overflow(out,ch);
};
template<typename T>
concept constant_buffer_output_stream_impl = requires(T&& out)
{
{obuffer_constant_size(io_reserve_type<typename std::remove_cvref_t<T>::char_type,std::remove_cvref_t<decltype(out)>>)}->std::same_as<std::size_t>;
obuffer_constant_flush_prepare(out);
};
template<typename T>
concept flush_output_stream_impl = requires(T&& out)
{
flush(out);
};
template<typename T>
concept fill_nc_output_stream_impl = requires(T&& out,std::size_t n,typename std::remove_cvref_t<T>::char_type ch)
{
fill_nc_define(out,n,ch);
};
template<typename T>
concept dynamic_output_stream_impl = requires(T&& out,std::size_t size,typename std::remove_cvref_t<T>::char_type* ptr)
{
oreserve(out,size);
oshrink_to_fit(out);
};
template<typename T>
concept zero_copy_input_stream_impl = requires(T&& in)
{
zero_copy_in_handle(in);
};
template<typename T>
concept zero_copy_output_stream_impl = requires(T&& out)
{
zero_copy_out_handle(out);
};
template<typename T>
concept redirect_stream_impl = requires(T&& h)
{
redirect_handle(h);
};
template<typename T>
concept status_stream_impl = requires(T&& stm)
{
typename std::remove_cvref_t<T>::status_type;
};
template<typename T>
concept scatter_input_stream_impl = requires(T&& in,io_scatters_t sp)
{
scatter_read(in,sp);
};
template<typename T>
concept scatter_output_stream_impl = requires(T&& out,io_scatters_t sp)
{
scatter_write(out,sp);
};
template<typename T>
concept scatter_constant_output_stream_impl = requires(T&& out,io_scatter_t const* sp)
{
scatter_constant_write<1>(out,sp);
};
template<std::integral ch_type>
struct dummy_buffer_output_stream
{
using char_type = ch_type;
};
template<std::integral char_type>
inline constexpr dummy_buffer_output_stream<char_type> io_value_handle(dummy_buffer_output_stream<char_type>) noexcept
{
return {};
}
template<std::integral char_type>
inline constexpr char_type* obuffer_begin(dummy_buffer_output_stream<char_type>) noexcept
{
return nullptr;
}
template<std::integral char_type>
inline constexpr char_type* obuffer_curr(dummy_buffer_output_stream<char_type>) noexcept
{
return nullptr;
}
template<std::integral char_type>
inline constexpr char_type* obuffer_end(dummy_buffer_output_stream<char_type>) noexcept
{
return nullptr;
}
template<std::integral char_type>
inline constexpr void obuffer_set_curr(dummy_buffer_output_stream<char_type>,char_type*) noexcept{}
template<std::integral char_type>
inline constexpr void obuffer_overflow(dummy_buffer_output_stream<char_type>,char_type) noexcept{}
template<std::integral char_type>
inline constexpr void write(dummy_buffer_output_stream<char_type>,char_type const*,char_type const*) noexcept{}
template<std::integral ch_type>
struct dummy_buffer_input_stream
{
using char_type = ch_type;
};
template<std::integral char_type>
inline constexpr dummy_buffer_input_stream<char_type> io_value_handle(dummy_buffer_input_stream<char_type>) noexcept
{
return {};
}
template<std::integral char_type>
inline constexpr char_type* ibuffer_begin(dummy_buffer_input_stream<char_type>) noexcept
{
return nullptr;
}
template<std::integral char_type>
inline constexpr char_type* ibuffer_curr(dummy_buffer_input_stream<char_type>) noexcept
{
return nullptr;
}
template<std::integral char_type>
inline constexpr char_type* ibuffer_end(dummy_buffer_input_stream<char_type>) noexcept
{
return nullptr;
}
template<std::integral char_type>
inline constexpr void ibuffer_set_curr(dummy_buffer_input_stream<char_type>,char_type*) noexcept{}
template<std::integral char_type>
inline constexpr bool ibuffer_underflow(dummy_buffer_input_stream<char_type>) noexcept
{
return true;
}
template<std::integral char_type>
inline constexpr char_type* read(dummy_buffer_input_stream<char_type>,char_type* first,char_type*) noexcept
{
return first;
}
#if 0
template<typename T>
concept async_input_stream64_impl = requires(T in,typename T::char_type* first,typename T::char_type* last,std::int_least64_t offset)
{
async_read_define64(in,first,last,offset,[](typename T::char_type*,::std::errc ec)
{
});
};
template<typename T>
concept async_input_stream64_impl = requires(T in,typename T::char_type* first,typename T::char_type* last,std::int_least64_t offset)
{
async_write_define64(in,first,last,offset,[](typename T::char_type*,::std::errc ec)
{
});
};
#endif
}
@@ -0,0 +1,10 @@
#pragma once
#include"type.h"
#include"parse_code.h"
#include"details.h"
#include"stream.h"
#include"operation_details.h"
#include"operation.h"
#include"decorator.h"
#include"strlike.h"
@@ -0,0 +1,195 @@
#pragma once
namespace fast_io
{
template<typename char_type, typename T>
concept contiguous_scannable = requires(char_type const* begin, char_type const* end, T t)
{
{scan_contiguous_define(io_reserve_type<char_type,T>,begin,end,t)}->std::same_as<parse_result<char_type const*>>;
};
template<typename char_type, typename T>
concept context_scannable = requires(char_type const* begin, char_type const* end, T t)
{
requires requires(typename std::remove_cvref_t<decltype(scan_context_type(io_reserve_type<char_type,T>))>::type st)
{
{scan_context_define(io_reserve_type<char_type,T>,st,begin,end,t)}->std::same_as<parse_result<char_type const*>>;
{scan_context_eof_define(io_reserve_type<char_type,T>,st,t)}->std::same_as<parse_code>;
};
};
template<typename char_type,typename T>
concept reserve_printable=std::integral<char_type>&&requires(T t,char_type* ptr)
{
{print_reserve_size(io_reserve_type<char_type,std::remove_cvref_t<T>>)}->std::convertible_to<std::size_t>;
{print_reserve_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,ptr,t)}->std::convertible_to<char_type*>;
};
template<typename char_type,typename T>
concept dynamic_reserve_printable=std::integral<char_type>&&requires(T t,char_type* ptr)
{
{print_reserve_size(io_reserve_type<char_type,std::remove_cvref_t<T>>,t)}->std::convertible_to<std::size_t>;
{print_reserve_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,ptr,t)}->std::convertible_to<char_type*>;
};
template<typename char_type,typename T>
concept printable_internal_shift=requires(T t)
{
{print_define_internal_shift(io_reserve_type<char_type,std::remove_cvref_t<T>>,t)}->std::same_as<std::size_t>;
};
template<typename char_type,typename T>
concept precise_reserve_printable=std::integral<char_type>&&(reserve_printable<char_type,T>||dynamic_reserve_printable<char_type,T>)&&requires(T t,char_type* ptr,std::size_t n)
{
{print_reserve_precise_size(io_reserve_type<char_type,std::remove_cvref_t<T>>,t)}->std::convertible_to<std::size_t>;
print_reserve_precise_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,ptr,n,t);
};
template<typename char_type,typename T>
concept printable=requires(::fast_io::details::dummy_buffer_output_stream<char_type> out,T t)
{
print_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,out,t);
};
template<typename char_type,typename T>
concept scatter_printable=requires(char_type ch,T&& t)
{
{print_scatter_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,::fast_io::freestanding::forward<T>(t))}->std::same_as<basic_io_scatter_t<char_type>>;
};
template<typename T>
concept alias_scannable=requires(T&& t)
{
scan_alias_define(io_alias,t);
};
template<typename T>
concept alias_printable=requires(T&& t)
{
print_alias_define(io_alias,::fast_io::freestanding::forward<T>(t));
};
template<typename char_type,typename T>
concept status_io_scan_forwardable=std::integral<char_type>&&requires(T t)
{
status_io_scan_forward(io_alias_type<char_type>,t);
};
template<typename char_type,typename T>
concept status_io_print_forwardable=std::integral<char_type>&&requires(T&& t)
{
status_io_print_forward(io_alias_type<char_type>,::fast_io::freestanding::forward<T>(t));
};
template<typename io_device,typename... Args>
concept io_controllable=requires(io_device device,Args&& ...args)
{
io_control(device,::fast_io::freestanding::forward<Args>(args)...);
};
struct manip_tag_t{};
template<typename T>
concept manipulator = requires(T t)
{
typename T::manip_tag;
};
template<typename T>
struct parameter
{
using manip_tag = manip_tag_t;
T reference;
};
template<std::integral char_type,typename output,typename value_type>
requires (printable<char_type,std::remove_cvref_t<value_type>>&&std::is_trivially_copyable_v<output>)
constexpr void print_define(io_reserve_type_t<char_type,parameter<value_type>>,output out, parameter<value_type> wrapper)
{
print_define(io_reserve_type<char_type,std::remove_cvref_t<value_type>>,out,wrapper.reference);
}
template<std::integral char_type,typename value_type>
requires reserve_printable<char_type,std::remove_cvref_t<value_type>>
constexpr std::size_t print_reserve_size(io_reserve_type_t<char_type,parameter<value_type>>)
{
return print_reserve_size(io_reserve_type<char_type,std::remove_cvref_t<value_type>>);
}
template<std::integral char_type,typename value_type>
requires dynamic_reserve_printable<char_type,std::remove_cvref_t<value_type>>
constexpr std::size_t print_reserve_size(io_reserve_type_t<char_type,parameter<value_type>>,parameter<value_type> para)
{
return print_reserve_size(io_reserve_type<char_type,std::remove_cvref_t<value_type>>,para.reference);
}
template<std::integral char_type,typename value_type>
requires (reserve_printable<char_type,std::remove_cvref_t<value_type>>||dynamic_reserve_printable<char_type,std::remove_cvref_t<value_type>>)
constexpr auto print_reserve_define(io_reserve_type_t<char_type,parameter<value_type>>,char_type* begin,parameter<value_type> para)
{
return print_reserve_define(io_reserve_type<char_type,std::remove_cvref_t<value_type>>,begin,para.reference);
}
template<std::integral char_type,typename value_type,typename Iter>
requires (printable_internal_shift<char_type,std::remove_cvref_t<value_type>>)
constexpr auto print_define_internal_shift(io_reserve_type_t<char_type,parameter<value_type>>,Iter begin,parameter<value_type> para)
{
return print_define_internal_shift(io_reserve_type<char_type,std::remove_cvref_t<value_type>>,begin,para.reference);
}
template<std::integral char_type,typename value_type>
requires precise_reserve_printable<char_type,std::remove_cvref_t<value_type>>
constexpr std::size_t print_reserve_precise_size(io_reserve_type_t<char_type,parameter<value_type>>,parameter<value_type> para)
{
return print_reserve_precise_size(io_reserve_type<char_type,std::remove_cvref_t<value_type>>,para.reference);
}
template<std::integral char_type,typename value_type,typename Iter>
requires precise_reserve_printable<char_type,std::remove_cvref_t<value_type>>
constexpr void print_reserve_precise_define(io_reserve_type_t<char_type,parameter<value_type>>,Iter begin,std::size_t n,parameter<value_type> para)
{
print_reserve_precise_define(io_reserve_type<char_type,std::remove_cvref_t<value_type>>,begin,n,para.reference);
}
template<std::integral char_type,typename value_type>
requires scatter_printable<char_type,std::remove_cvref_t<value_type>>
constexpr auto print_scatter_define(io_reserve_type_t<char_type,parameter<value_type>>,parameter<value_type> para)
{
return print_scatter_define(io_reserve_type<char_type,std::remove_cvref_t<value_type>>,para.reference);
}
template<typename char_type,typename T>
concept iterative_scannable = ::std::integral<char_type>&&requires(T& t,char_type const* buffer_curr,char_type const* buffer_end)
{
{scan_iterative_init_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,t)};
{scan_iterative_next_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,t,buffer_curr,buffer_end)}->std::same_as<parse_result<char_type const*>>;
{scan_iterative_eof_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,t)}->std::same_as<fast_io::parse_code>;
};
template<typename char_type,typename T>
concept iterative_contiguous_scannable = ::std::integral<char_type>&&requires(T t,char_type const* buffer_curr,char_type const* buffer_end)
{
{scan_iterative_contiguous_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,t,buffer_curr,buffer_end)}->std::same_as<parse_result<char_type const*>>;
};
template<typename char_type,typename T>
concept precise_reserve_scannable = ::std::integral<char_type>&&requires(char_type const* buffer_curr,T t)
{
{scan_precise_reserve_size(io_reserve_type<char_type,std::remove_cvref_t<T>>)}->::std::same_as<::std::size_t>;
scan_precise_reserve_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,buffer_curr,t);
};
template<typename char_type,typename T>
concept precise_reserve_scannable_no_error = precise_reserve_scannable<char_type,T>&&requires(char_type const* buffer_curr,T t)
{
{scan_precise_reserve_define(io_reserve_type<char_type,std::remove_cvref_t<T>>,buffer_curr,t)}->::std::same_as<void>;
};
namespace manipulators
{}
namespace mnp=manipulators;
}
@@ -0,0 +1,158 @@
#pragma once
namespace fast_io::details
{
template<typename ch_type>
concept character = std::integral<ch_type>&&(std::same_as<ch_type,char>||std::same_as<ch_type,wchar_t>||std::same_as<ch_type,char16_t>||
std::same_as<ch_type,char8_t>||std::same_as<ch_type,char32_t>);
template<typename T>
concept c_str_pointer = std::same_as<T,char const*>||std::same_as<T,char8_t const*>||std::same_as<T,wchar_t const*>||
std::same_as<T,char16_t const*>||std::same_as<T,char32_t const*>;
}
namespace fast_io
{
template<typename T>
concept type_has_c_str_method = requires(T&& t)
{
{t.c_str()}->::fast_io::details::c_str_pointer;
};
template<typename T>
concept constructible_to_os_c_str = type_has_c_str_method<T>||(std::is_array_v<std::remove_reference_t<T>>)||requires(T&& t)
{
{t.length()};
{t.substr()};
{t.data()};
};
template<typename T>
concept constructible_to_os_c_str_or_nullptr = constructible_to_os_c_str<T>||requires(T&& t)
{
{t.is_nullptr()}->std::same_as<bool>;
};
namespace manipulators
{
template<std::integral ch_type>
struct basic_os_c_str
{
using char_type = ch_type;
char_type const* ptr{};
inline constexpr char_type const* c_str() const noexcept
{
return ptr;
}
};
template<::std::integral char_type>
inline constexpr basic_os_c_str<char_type> os_c_str(char_type const* cstr) noexcept
{
return {cstr};
}
inline constexpr void os_c_str(decltype(nullptr))=delete;
template<std::integral ch_type>
struct basic_os_c_str_or_nullptr
{
using char_type = ch_type;
char_type const* ptr{};
inline constexpr char_type const* c_str() const noexcept
{
return ptr;
}
inline constexpr bool is_nullptr() const noexcept
{
return ptr==nullptr;
}
};
template<std::integral char_type>
inline constexpr basic_os_c_str_or_nullptr<char_type> os_c_str_or_nullptr(char_type const* cstr) noexcept
{
return {cstr};
}
template<std::integral ch_type>
struct basic_os_c_str_with_known_size
{
using char_type = ch_type;
char_type const* ptr{};
std::size_t n{};
inline constexpr char_type const* c_str() const noexcept
{
return ptr;
}
inline constexpr std::size_t size() const noexcept
{
return n;
}
inline constexpr char_type const* data() const noexcept
{
return ptr;
}
inline constexpr char_type const* begin() const noexcept
{
return ptr;
}
inline constexpr char_type const* end() const noexcept
{
return ptr+n;
}
};
template<std::integral char_type>
inline constexpr basic_os_c_str_with_known_size<char_type> os_c_str_with_known_size(char_type const* cstr,std::size_t n) noexcept
{
return {cstr,n};
}
inline constexpr void os_c_str_with_known_size(decltype(nullptr),std::size_t)=delete;
template<std::integral ch_type>
struct basic_os_str_known_size_without_null_terminated
{
using char_type = ch_type;
char_type const* ptr{};
std::size_t n{};
inline constexpr std::size_t size() const noexcept
{
return n;
}
inline constexpr char_type const* data() const noexcept
{
return ptr;
}
inline constexpr char_type const* begin() const noexcept
{
return ptr;
}
inline constexpr char_type const* end() const noexcept
{
return ptr+n;
}
};
template<std::integral char_type>
inline constexpr basic_os_str_known_size_without_null_terminated<char_type> os_str_known_size_without_null_terminated(char_type const* cstr,std::size_t n) noexcept
{
return {cstr,n};
}
template<std::integral char_type>
inline constexpr basic_os_str_known_size_without_null_terminated<char_type> os_str_known_size_without_null_terminated(char_type const* cstr, char_type const* end) noexcept
{
return {cstr,static_cast<::std::size_t>(end-cstr)};
}
inline constexpr void os_str_known_size_without_null_terminated(decltype(nullptr),std::size_t)=delete;
}
}
@@ -0,0 +1,24 @@
#pragma once
namespace fast_io
{
enum class parse_code:char unsigned
{
ok = 0,
end_of_file = 1,
partial = 2,
invalid = 3,
overflow = 4
};
template<typename Iter>
struct parse_result
{
using iterator = Iter;
iterator iter;
parse_code code;
};
}
@@ -0,0 +1,172 @@
#pragma once
namespace fast_io
{
template<typename T>
concept stream = details::input_stream_impl<T>||details::output_stream_impl<T>;
template<typename T>
concept input_stream = stream<T>&&details::input_stream_impl<T>;
template<typename T>
concept output_stream = stream<T>&&details::output_stream_impl<T>;
template<typename T>
concept output_stream_with_writeln = output_stream<T>&&requires(T&& t,typename std::remove_cvref_t<T>::char_type const* p)
{
writeln(t,p,p);
};
template<typename T>
concept mutex_stream = stream<T>&&details::mutex_stream_impl<T>;
template<typename T>
concept random_access_stream = stream<T>&&details::random_access_stream_impl<T>;
template<typename T>
concept io_stream = input_stream<T>&&output_stream<T>;
template<typename T>
concept flush_output_stream = output_stream<T>&&details::flush_output_stream_impl<T>;
template<typename T>
concept buffer_input_stream = input_stream<T>&&details::buffer_input_stream_impl<T>;
template<typename T>
concept contiguous_input_stream = buffer_input_stream<T>&&details::contiguous_input_stream_impl<T>;
template<typename T>
concept buffer_output_stream = output_stream<T>&&details::buffer_output_stream_impl<T>;
template<typename T>
concept constant_buffer_output_stream = buffer_output_stream<T>&&details::constant_buffer_output_stream_impl<T>;
template<typename T>
concept contiguous_output_stream = buffer_output_stream<T>&&details::contiguous_output_stream_impl<T>;
template<typename T>
concept buffer_io_stream = buffer_input_stream<T>&&buffer_output_stream<T>&&io_stream<T>;
template<typename T>
concept dynamic_output_stream = buffer_output_stream<T>&&details::dynamic_output_stream_impl<T>;
/*
noline_buffer_output_stream ensures obuffer_begin(out)<=obuffer_curr(out)<=obuffer_end(out)
line_buffer_output_stream may end up a situation obuffer_curr(out)>obuffer_end(out), triggering overflow.
That is how glibc implements FILE*.
In fast_io, all fast_io directly supported stream ensures noline_buffer_output_stream
*/
template<typename T>
concept noline_buffer_output_stream = buffer_output_stream<T>&&!requires(T t)
{
{obuffer_is_line_buffering(t)}->std::convertible_to<bool>;
};
template<typename T>
concept zero_copy_input_stream = input_stream<T>&&details::zero_copy_input_stream_impl<T>;
template<typename T>
concept zero_copy_output_stream = output_stream<T>&&details::zero_copy_output_stream_impl<T>;
template<typename T>
concept zero_copy_io_stream = zero_copy_input_stream<T>&&zero_copy_output_stream<T>;
template<typename T>
concept scatter_input_stream = input_stream<T>&&details::scatter_input_stream_impl<T>;
template<typename T>
concept scatter_output_stream = output_stream<T>&&details::scatter_output_stream_impl<T>;
template<typename T>
concept scatter_constant_output_stream = output_stream<T>&&details::scatter_constant_output_stream_impl<T>;
#if 0
template<typename T>
concept async_stream = details::async_input_stream_impl<T>||details::async_output_stream_impl<T>;
template<typename T>
concept async_input_stream = async_stream<T>&&details::async_input_stream_impl<T>;
template<typename T>
concept async_output_stream = async_stream<T>&&details::async_output_stream_impl<T>;
template<typename T>
concept async_io_stream = async_input_stream<T>&&async_output_stream<T>;
template<typename T>
concept async_scatter_input_stream = async_stream<T>&&details::async_scatter_input_stream_impl<T>;
template<typename T>
concept async_scatter_output_stream = async_stream<T>&&details::async_scatter_output_stream_impl<T>;
template<typename T>
concept async_scatter_io_stream = async_input_stream<T>&&async_scatter_output_stream<T>;
#endif
template<typename T>
concept closable_stream = stream<T>&&requires(T t)
{
{t.close()}->std::same_as<void>;
};
template<typename T>
concept secure_clear_requirement_stream = stream<T>&&requires(T stm)
{
require_secure_clear(stm);
};
template<typename T>
concept redirect_stream = stream<T>&&details::redirect_stream_impl<T>;
template<typename T>
concept capacity_available_buffer_input_stream = buffer_input_stream<T>&&requires(T stm)
{
{ibuffer_cap(stm)}->std::convertible_to<typename std::remove_cvref_t<T>::char_type*>;
};
template<typename T>
concept value_based_stream = requires(T t)
{
{io_value_handle(t)};
}&&
(std::is_trivially_copyable_v<T> ||
requires(T t)
{
typename T::native_handle_type;
t.release();
t.native_handle();
requires std::is_trivially_copyable_v<typename T::native_handle_type>;
});
template<typename T>
concept try_get_input_stream=input_stream<T>&&requires(T in)
{
{try_get(in)}->std::convertible_to<try_get_result<typename T::char_type>>;
};
/*
status streams deal with special stream types like streams which need locale
You can define your own behavior with it
*/
template<typename T>
concept status_output_stream = requires(T out)
{
print_status_define<false>(out,1,1,1,1,1,1,1,1,1,1);
print_status_define<true>(out,1,1,1,1,1,1,1,1,1,1);
};
/*
input requires a whole overhual because C++ exception is horrible.
*/
template<typename T>
concept status_input_stream = requires(T in)
{
{scan_status_define(in)}->std::convertible_to<bool>;
};
}
@@ -0,0 +1,81 @@
#pragma once
namespace fast_io
{
template<std::integral char_type,typename T>
struct io_strlike_type_t
{
explicit constexpr io_strlike_type_t() noexcept = default;
};
template<std::integral char_type,typename T>
inline constexpr io_strlike_type_t<char_type,T> io_strlike_type{};
namespace details
{
template<typename char_type,typename T>
concept buffer_strlike_impl = requires(T& t)
{
{strlike_begin(io_strlike_type<char_type,T>,t)};
{strlike_curr(io_strlike_type<char_type,T>,t)};
{strlike_end(io_strlike_type<char_type,T>,t)};
requires requires(decltype(strlike_begin(io_strlike_type<char_type,T>,t)) ptr)
{
{strlike_set_curr(io_strlike_type<char_type,T>,t,ptr)};
};
requires requires(std::size_t n)
{
{strlike_reserve(io_strlike_type<char_type,T>,t,n)};
};
};
}
template<typename char_type,typename T>
concept strlike = std::integral<char_type>&&std::is_default_constructible_v<T>&&(requires(char_type const* first)
{
strlike_construct_define(io_strlike_type<char_type,T>,first,first);
}||::fast_io::details::buffer_strlike_impl<char_type,T>);
template<typename char_type,typename T>
concept single_character_constructible_strlike = strlike<char_type,T>&&requires(char_type ch)
{
strlike_construct_single_character_define(io_strlike_type<char_type,T>,ch);
};
template<typename char_type,typename T>
concept alias_strlike = requires(T& t)
{
strlike_alias_define(io_alias,t);
};
template<typename char_type,typename T>
concept buffer_strlike = strlike<char_type,T> && requires(T& t)
{
{strlike_begin(io_strlike_type<char_type,T>,t)};
{strlike_curr(io_strlike_type<char_type,T>,t)};
{strlike_end(io_strlike_type<char_type,T>,t)};
requires requires(decltype(strlike_begin(io_strlike_type<char_type,T>,t)) ptr)
{
{strlike_set_curr(io_strlike_type<char_type,T>,t,ptr)};
};
requires requires(std::size_t n)
{
{strlike_reserve(io_strlike_type<char_type,T>,t,n)};
};
};
template<typename char_type,typename T>
concept auxiliary_strlike = strlike<char_type,T> && requires(T& t,char_type ch,char_type const* ptr)
{
strlike_push_back(io_strlike_type<char_type,T>,t,ch);
strlike_append(io_strlike_type<char_type,T>,t,ptr,ptr);
};
template<typename char_type,typename T>
concept sso_buffer_strlike = buffer_strlike<char_type,T> && requires()
{
{strlike_sso_size(io_strlike_type<char_type,T>)}->std::same_as<std::size_t>;
};
}
@@ -0,0 +1,91 @@
#pragma once
namespace fast_io
{
template<typename T>
struct basic_io_scatter_t
{
using value_type = T;
T const* base;
std::size_t len;
};
//should be binary compatible with POSIX's iovec
using io_scatter_t = basic_io_scatter_t<void>;
using io_scatters_t = basic_io_scatter_t<io_scatter_t>;
struct io_scatter_status_t
{
std::size_t total_size;
std::size_t position;
std::size_t position_in_scatter;
};
template<typename T>
struct basic_message_hdr
{
T const *name; /* Optional address */
std::size_t namelen; /* Size of address */
basic_io_scatter_t<T> const* iov; /* Scatter/gather array */
std::size_t iovlen; /* # elements in msg_iov */
T const *control; /* Ancillary data, see below */
std::size_t controllen; /* Ancillary data buffer len */
int flags; /* Flags (unused) */
inline operator basic_message_hdr<void>() const noexcept requires(!std::same_as<T,void>)
{
return {name,namelen*sizeof(T),iov,iovlen*sizeof(T),control,controllen,flags};
}
};
using message_hdr = basic_message_hdr<void>;
//should be binary compatible with POSIX's msghdr
template<typename T>
struct io_type_t
{
using type = T;
};
template<typename T>
inline constexpr io_type_t<T> io_type{};
template<std::integral char_type>
struct cross_code_cvt_t
{
using value_type = char_type;
basic_io_scatter_t<value_type> scatter;
};
template<std::integral char_type,typename T>
struct io_reserve_type_t
{
explicit constexpr io_reserve_type_t() noexcept =default;
};
template<std::integral char_type,typename T>
inline constexpr io_reserve_type_t<char_type,T> io_reserve_type{};
struct io_alias_t
{
explicit constexpr io_alias_t() noexcept =default;
};
inline constexpr io_alias_t io_alias{};
template<std::integral char_type>
struct io_alias_type_t
{
explicit constexpr io_alias_type_t() noexcept = default;
};
template<std::integral char_type>
inline constexpr io_alias_type_t<char_type> io_alias_type{};
template<std::integral char_type>
struct try_get_result
{
char_type ch;
bool eof;
};
}
@@ -0,0 +1,62 @@
#pragma once
namespace fast_io
{
enum class dll_mode:std::uint_least32_t
{
none=0,
posix_rtld_lazy=static_cast<std::uint_least32_t>(1)<<0,
posix_rtld_now=static_cast<std::uint_least32_t>(1)<<1,
posix_rtld_binding_mask=static_cast<std::uint_least32_t>(1)<<2,
posix_rtld_global=static_cast<std::uint_least32_t>(1)<<3,
posix_rtld_local=static_cast<std::uint_least32_t>(1)<<4,
posix_rtld_nodelete=static_cast<std::uint_least32_t>(1)<<5,
posix_rtld_noload=static_cast<std::uint_least32_t>(1)<<6,
posix_rtld_deepbind=static_cast<std::uint_least32_t>(1)<<7,
win32_dont_resolve_dll_references=static_cast<std::uint_least32_t>(1)<<10,
win32_load_ignore_code_authz_level=static_cast<std::uint_least32_t>(1)<<11,
win32_load_library_as_datafile=static_cast<std::uint_least32_t>(1)<<12,
win32_load_library_as_datafile_exclusive=static_cast<std::uint_least32_t>(1)<<13,
win32_load_library_as_image_resource=static_cast<std::uint_least32_t>(1)<<14,
win32_load_library_search_application_dir=static_cast<std::uint_least32_t>(1)<<15,
win32_load_library_search_default_dirs=static_cast<std::uint_least32_t>(1)<<16,
win32_load_library_search_dll_load_dir=static_cast<std::uint_least32_t>(1)<<17,
win32_load_library_search_system32=static_cast<std::uint_least32_t>(1)<<18,
win32_load_library_search_user_dirs=static_cast<std::uint_least32_t>(1)<<19,
win32_load_with_altered_search_path=static_cast<std::uint_least32_t>(1)<<20,
win32_load_library_require_signed_target=static_cast<std::uint_least32_t>(1)<<21,
win32_load_library_safe_current_dirs=static_cast<std::uint_least32_t>(1)<<22
};
constexpr dll_mode operator&(dll_mode x, dll_mode y) noexcept
{
using utype = typename std::underlying_type<dll_mode>::type;
return static_cast<dll_mode>(static_cast<utype>(x) & static_cast<utype>(y));
}
constexpr dll_mode operator|(dll_mode x, dll_mode y) noexcept
{
using utype = typename std::underlying_type<dll_mode>::type;
return static_cast<dll_mode>(static_cast<utype>(x) | static_cast<utype>(y));
}
constexpr dll_mode operator^(dll_mode x, dll_mode y) noexcept
{
using utype = typename std::underlying_type<dll_mode>::type;
return static_cast<dll_mode>(static_cast<utype>(x) ^ static_cast<utype>(y));
}
constexpr dll_mode operator~(dll_mode x) noexcept
{
using utype = typename std::underlying_type<dll_mode>::type;
return static_cast<dll_mode>(~static_cast<utype>(x));
}
inline constexpr dll_mode& operator&=(dll_mode& x, dll_mode y) noexcept{return x=x&y;}
inline constexpr dll_mode& operator|=(dll_mode& x, dll_mode y) noexcept{return x=x|y;}
inline constexpr dll_mode& operator^=(dll_mode& x, dll_mode y) noexcept{return x=x^y;}
}
@@ -0,0 +1,21 @@
#pragma once
namespace fast_io
{
template<buffer_output_stream source_type>
constexpr basic_io_scatter_t<typename std::remove_cvref_t<source_type>::char_type> print_alias_define(io_alias_t,manip::drainage<source_type&> source)
{
auto bg{obuffer_begin(source.reference)};
auto curr{obuffer_curr(source.reference)};
return {bg,static_cast<std::size_t>(curr-bg)};
}
template<output_stream dest_type,output_stream source_type>
inline constexpr void drain(dest_type&& dest,source_type&& source)
{
print_freestanding(::std::forward<dest_type>(dest),drainage(source));
}
}
@@ -0,0 +1,166 @@
#pragma once
//std::string is not usable in freestanding environments and cause problems for this library
//This is a very simple stuff for internal use
namespace fast_io
{
template<std::integral ch_type>
class dynamic_io_buffer
{
public:
using char_type = ch_type;
using pointer = char_type*;
pointer buffer_begin=nullptr,buffer_curr=nullptr,buffer_end=nullptr;
constexpr dynamic_io_buffer()=default;
dynamic_io_buffer(dynamic_io_buffer const&)=delete;
dynamic_io_buffer& operator=(dynamic_io_buffer const&)=delete;
#if __cpp_constexpr_dynamic_alloc >= 201907L
constexpr
#endif
~dynamic_io_buffer()
{
details::deallocate_iobuf_space<false,char_type>(buffer_begin,buffer_end-buffer_begin);
}
};
template<std::integral char_type>
[[nodiscard]] constexpr char_type* obuffer_begin(dynamic_io_buffer<char_type>& ob) noexcept
{
return ob.buffer_begin;
}
template<std::integral char_type>
[[nodiscard]] constexpr char_type* obuffer_curr(dynamic_io_buffer<char_type>& ob) noexcept
{
return ob.buffer_curr;
}
template<std::integral char_type>
[[nodiscard]] constexpr char_type* obuffer_end(dynamic_io_buffer<char_type>& ob) noexcept
{
return ob.buffer_end;
}
template<std::integral char_type>
inline constexpr void obuffer_set_curr(dynamic_io_buffer<char_type>& ob,char_type* ptr) noexcept
{
ob.buffer_curr=ptr;
}
namespace details
{
template<std::integral char_type>
inline constexpr void dynamic_io_buffer_oreallocate_impl(dynamic_io_buffer<char_type>& ob,std::size_t size) noexcept
{
auto new_space{allocate_iobuf_space<char_type>(size)};
std::size_t ptr_diff{static_cast<std::size_t>(ob.buffer_curr-ob.buffer_begin)};
non_overlapped_copy_n(ob.buffer_begin,ptr_diff,new_space);
deallocate_iobuf_space<false,char_type>(ob.buffer_begin,ob.buffer_end-ob.buffer_begin);
ob.buffer_begin=new_space;
ob.buffer_curr=new_space+ptr_diff;
ob.buffer_end=new_space+size;
}
template<std::integral char_type>
inline constexpr void dynamic_io_buffer_grow_with_new_size(dynamic_io_buffer<char_type>& ob,std::size_t new_size) noexcept
{
std::size_t new_capacity{static_cast<std::size_t>(ob.buffer_end-ob.buffer_begin)};
constexpr std::size_t cap_max{SIZE_MAX/2};
if(new_capacity>cap_max)
new_capacity=SIZE_MAX;
else
new_capacity*=2;
if(new_capacity<new_size)
new_capacity=new_size;
dynamic_io_buffer_oreallocate_impl(ob,new_capacity);
}
template<std::integral char_type>
inline constexpr void dynamic_io_buffer_overflow_impl(dynamic_io_buffer<char_type>& ob,char_type ch) noexcept
{
std::size_t new_capacity{static_cast<std::size_t>(ob.buffer_end-ob.buffer_begin)};
constexpr std::size_t cap_max{SIZE_MAX/2};
if(new_capacity>cap_max)
new_capacity=SIZE_MAX;
else
new_capacity*=2;
dynamic_io_buffer_oreallocate_impl(ob,new_capacity);
*ob.buffer_curr=ch;
++ob.buffer_curr;
}
template<std::integral char_type,::std::forward_iterator Iter>
inline constexpr void dynamic_io_buffer_write_impl_unhappy_iter(dynamic_io_buffer<char_type>& ob,
Iter first,std::size_t diff) noexcept
{
dynamic_io_buffer_grow_with_new_size(ob,ob.buffer_end-ob.buffer_begin+diff);
ob.buffer_curr=non_overlapped_copy_n(first,diff,ob.buffer_curr);
}
template<::std::forward_iterator Iter>
inline constexpr void dynamic_io_buffer_write_impl_unhappy(dynamic_io_buffer<::std::iter_value_t<Iter>>& ob,
Iter first,std::size_t diff) noexcept
{
if constexpr(::std::contiguous_iterator<Iter>)
{
auto const * ptr{::std::to_address(first)};
dynamic_io_buffer_write_impl_unhappy_iter(ob,ptr,diff);
}
else
dynamic_io_buffer_write_impl_unhappy_iter(ob,first,diff);
}
}
template<std::integral ch_type>
inline constexpr void oreserve(dynamic_io_buffer<ch_type>& ob,std::size_t new_capacity) noexcept
{
if(static_cast<std::size_t>(ob.buffer_end-ob.buffer_begin)<=new_capacity)
return;
details::dynamic_io_buffer_oreallocate_impl(ob,new_capacity);
}
template<std::integral ch_type>
inline constexpr void oshrink_to_fit(dynamic_io_buffer<ch_type>& ob) noexcept
{
if(ob.buffer_curr==ob.buffer_end)
return;
details::dynamic_io_buffer_oreallocate_impl(ob,ob.buffer_curr-ob.buffer_begin);
}
template<std::integral ch_type>
inline constexpr void obuffer_overflow(dynamic_io_buffer<ch_type>& ob,ch_type ch) noexcept
{
details::dynamic_io_buffer_overflow_impl(ob,ch);
}
template<std::integral ch_type,::std::forward_iterator Iter>
requires ((std::same_as<ch_type,char>&&::std::contiguous_iterator<Iter>)||
std::same_as<ch_type,::std::iter_value_t<Iter>>)
inline constexpr void write(dynamic_io_buffer<ch_type>& ob,Iter first,Iter last) noexcept
{
if constexpr(!std::same_as<ch_type,::std::iter_value_t<Iter>>)
{
write(ob,
reinterpret_cast<char const*>(::std::to_address(first)),
reinterpret_cast<char const*>(::std::to_address(last)));
}
else if constexpr(::std::contiguous_iterator<Iter>&&!std::is_pointer_v<std::remove_cvref_t<Iter>>)
{
write(ob,::std::to_address(first),::std::to_address(last));
}
else
{
std::size_t diff{static_cast<std::size_t>(last-first)};
std::size_t remain_space{static_cast<std::size_t>(ob.buffer_end-ob.buffer_curr)};
if(remain_space<diff)
{
details::dynamic_io_buffer_write_impl_unhappy(ob,first,diff);
return;
}
ob.buffer_curr=details::non_overlapped_copy(first,last,ob.buffer_begin);
}
}
}
@@ -0,0 +1,59 @@
#pragma once
namespace fast_io::details
{
template<std::integral char_type>
inline constexpr bool exec_charset_is_ebcdic() noexcept
{
if constexpr(std::same_as<std::remove_cvref_t<char_type>,char>)
{
return static_cast<char8_t>('A')!=u8'A';
}
else if constexpr(std::same_as<std::remove_cvref_t<char_type>,wchar_t>)
{
if constexpr(sizeof(wchar_t)==sizeof(char16_t))
{
constexpr char16_t value{static_cast<char16_t>(L'A')};
constexpr char16_t swapped{::fast_io::byte_swap(value)};
return value!=u'A'&&swapped!=u'A';
}
else if constexpr(sizeof(wchar_t)==sizeof(char32_t))
{
constexpr char32_t value{static_cast<char32_t>(L'A')};
constexpr char32_t swapped{::fast_io::byte_swap(value)};
return value!=U'A'&&swapped!=U'A';
}
else
{
return static_cast<char32_t>(L'A')!=U'A';
}
}
else
{
return false;
}
}
template<std::integral char_type>
inline constexpr bool is_ebcdic{exec_charset_is_ebcdic<char_type>()};
inline constexpr bool wexec_charset_is_utf_none_native_endian() noexcept
{
if constexpr(sizeof(wchar_t)==sizeof(char16_t))
{
constexpr char16_t value{static_cast<char16_t>(L'A')};
constexpr char16_t swapped{::fast_io::byte_swap(value)};
return value!=u'A'&&swapped==u'A';
}
else
{
constexpr char32_t value{static_cast<char32_t>(L'A')};
constexpr char32_t swapped{::fast_io::byte_swap(value)};
return value!=U'A'&&swapped==U'A';
}
}
inline constexpr bool wide_is_none_utf_endian{wexec_charset_is_utf_none_native_endian()};
}
@@ -0,0 +1,6 @@
#pragma once
namespace fast_io::details
{
struct empty{};
}
@@ -0,0 +1,44 @@
#pragma once
namespace fast_io
{
enum class access_how:std::uint_fast8_t
{
f_ok=0,
x_ok=1,
w_ok=2,
r_ok=4
};
constexpr access_how operator&(access_how x, access_how y) noexcept
{
using utype = typename std::underlying_type<access_how>::type;
return static_cast<access_how>(static_cast<utype>(x) & static_cast<utype>(y));
}
constexpr access_how operator|(access_how x, access_how y) noexcept
{
using utype = typename std::underlying_type<access_how>::type;
return static_cast<access_how>(static_cast<utype>(x) | static_cast<utype>(y));
}
constexpr access_how operator^(access_how x, access_how y) noexcept
{
using utype = typename std::underlying_type<access_how>::type;
return static_cast<access_how>(static_cast<utype>(x) ^ static_cast<utype>(y));
}
constexpr access_how operator~(access_how x) noexcept
{
using utype = typename std::underlying_type<access_how>::type;
return static_cast<access_how>(~static_cast<utype>(x));
}
inline constexpr access_how& operator&=(access_how& x, access_how y) noexcept{return x=x&y;}
inline constexpr access_how& operator|=(access_how& x, access_how y) noexcept{return x=x|y;}
inline constexpr access_how& operator^=(access_how& x, access_how y) noexcept{return x=x^y;}
}
@@ -0,0 +1,62 @@
#pragma once
namespace fast_io
{
enum class file_lock_mode:char unsigned
{
shared_lock,
exclusive_lock,
unlock,
};
template<std::signed_integral T>
struct basic_flock_request
{
using int_type = T;
file_lock_mode type=file_lock_mode::exclusive_lock;
seekdir whence=seekdir::cur;
int_type start=0;
int_type len=0;
};
using flock_request_l64 = basic_flock_request<::std::int_least64_t>;
struct nop_file_lock
{
template<typename RequestType>
constexpr void lock(RequestType const&) noexcept{}
template<typename RequestType>
constexpr void unlock(RequestType const&) noexcept{}
template<typename RequestType>
constexpr bool try_lock(RequestType const&) noexcept
{
return true;
}
};
template<typename FilelockT,typename RequestT>
requires requires(FilelockT t,RequestT& lk)
{
t.lock(lk);
t.unlock(lk);
}
struct file_lock_guard
{
using file_lock_type = FilelockT;
using request_type = RequestT;
file_lock_type lock;
request_type request;
explicit constexpr file_lock_guard(file_lock_type const& lk,request_type const& flk):lock(lk),request(flk)
{
lock.lock(request);
}
file_lock_guard(file_lock_guard const&)=delete;
file_lock_guard& operator=(file_lock_guard const&)=delete;
constexpr ~file_lock_guard()
{
lock.unlock(request);
}
};
}
@@ -0,0 +1,5 @@
#pragma once
#include"access_how.h"
#include"utime_flags.h"
#include"flock.h"
@@ -0,0 +1,20 @@
#pragma once
namespace fast_io
{
enum class utime_flags:std::uint_fast8_t
{
none,now,omit
};
struct unix_timestamp_option
{
utime_flags flags{utime_flags::omit};
unix_timestamp timestamp{};
constexpr unix_timestamp_option() noexcept=default;
constexpr unix_timestamp_option(unix_timestamp ts) noexcept:flags(utime_flags::none),timestamp(ts){}
constexpr unix_timestamp_option(utime_flags fg) noexcept:flags(fg){}
};
}
@@ -0,0 +1,80 @@
#pragma once
namespace fast_io
{
struct error
{
using value_type = std::uintptr_t;
value_type domain{};
value_type code{};
};
inline constexpr bool operator==(error e1,error e2) noexcept
{
return e1.domain==e2.domain&&e1.code==e2.code;
}
inline constexpr bool operator!=(error e1,error e2) noexcept
{
return !(e1==e2);
}
template<typename T>
struct error_type_t
{
explicit inline constexpr error_type_t() noexcept = default;
};
template<typename T>
inline constexpr error_type_t<T> error_type{};
template<typename T>
concept error_domain = std::is_trivially_copyable_v<T> && sizeof(T)<=sizeof(std::uintptr_t) &&
requires(error e,T t)
{
{domain_define(error_type<T>)}->std::same_as<std::uintptr_t>;
{equivalent_define(error_type<T>,e,t)}->std::same_as<bool>;
#if 0
{to_code_define(error_type<T>,e)}->std::same_as<T>;
#endif
};
template<error_domain D>
inline constexpr bool is_domain(error e) noexcept
{
constexpr std::uintptr_t v{error_domain_define(error_type<D>)};
return v==e.domain;
}
template<error_domain D>
inline constexpr D to_code(error e) noexcept
{
return to_code_define(error_type<D>,e);
}
template<error_domain D>
inline constexpr bool operator==(error e,D t) noexcept
{
return equivalent_define(error_type<D>,e,t);
}
template<error_domain D>
inline constexpr bool operator==(D t,error e) noexcept
{
return equivalent_define(error_type<D>,e,t);
}
template<error_domain D>
inline constexpr bool operator!=(error e,D t) noexcept
{
return !equivalent_define(error_type<D>,e,t);
}
template<error_domain D>
inline constexpr bool operator!=(D t,error e) noexcept
{
return !equivalent_define(error_type<D>,e,t);
}
}
@@ -0,0 +1,53 @@
#pragma once
/*
Referenced from libstdc++
https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/include/bits/move.h
*/
/*
C++ freestanding does not provide ::std::addressof, ::std::move and ::std::forward. We need to define them by ourselves.
*/
namespace fast_io::freestanding
{
template <typename T>
#if __has_cpp_attribute(__gnu__::__always_inline__)
[[__gnu__::__always_inline__]]
#elif __has_cpp_attribute(msvc::forceinline)
[[msvc::forceinline]]
#endif
[[nodiscard]] inline constexpr T *
addressof(T &r) noexcept
{
return __builtin_addressof(r); // death to compilers which do not support __builtin_addressof
}
template <typename T>
T const *addressof(T const &&) = delete;
template <typename T>
#if __has_cpp_attribute(__gnu__::__always_inline__)
[[__gnu__::__always_inline__]]
#elif __has_cpp_attribute(msvc::forceinline)
[[msvc::forceinline]]
#endif
[[nodiscard]] inline constexpr T &&
forward(::std::remove_reference_t<T> &t) noexcept
{
return static_cast<T &&>(t);
}
template <typename T>
#if __has_cpp_attribute(__gnu__::__always_inline__)
[[__gnu__::__always_inline__]]
#elif __has_cpp_attribute(msvc::forceinline)
[[msvc::forceinline]]
#endif
[[nodiscard]] inline constexpr typename ::std::remove_reference<T>::type &&
move(T &&t) noexcept
{
return static_cast<typename ::std::remove_reference<T>::type &&>(t);
}
} // namespace fast_io::freestanding

Some files were not shown because too many files have changed in this diff Show More