Using PathView to pass paths to APIs #2
+3
-2
@@ -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)
|
||||
|
||||
@@ -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, "\\", "/");
|
||||
@@ -35,8 +35,10 @@ TL_DECLARE_STRING_VECTOR(UncParseSeparators, "\\", "/");
|
||||
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 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>());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
@@ -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,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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
+29
-41
@@ -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::vector<CentralDirectoryRecord> m_records;
|
||||
|
||||
tl::memory_buffer m_buffer;
|
||||
tl::unique_ptr<zip> m_zipArchive;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
+2
-2
@@ -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
@@ -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
@@ -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
@@ -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()*/)
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
|
||||
+4
-4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,33 +190,19 @@ 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
@@ -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);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
insert_final_newline = true
|
||||
@@ -0,0 +1,7 @@
|
||||
# editorconfig
|
||||
321f2fa166c804c1ddb0aa5cf9afc8cde7e3be43
|
||||
# clang-format
|
||||
395c9c7f67771c64ae673caa1428f848fd8242e7
|
||||
458c2f98c9fee122dd01e04d73b76786b13498d0
|
||||
b9db56983496403e8cdd065c6d9e5300eccb05b2
|
||||
e3c089ffca7836c3d7d3a022afbbc0f98010a946
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user