Skip to content

Commit

Permalink
refs #73, performance optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
gulrak committed Sep 30, 2020
1 parent d8abf14 commit c8cfcf8
Showing 1 changed file with 76 additions and 31 deletions.
107 changes: 76 additions & 31 deletions include/ghc/filesystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
#define GHC_FILESYSTEM_VERSION 10304L
#define GHC_FILESYSTEM_VERSION 10305L

#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND))
#define GHC_WITH_EXCEPTIONS
Expand Down Expand Up @@ -229,8 +229,17 @@ class path_helper_base
template <typename char_type>
constexpr char_type path_helper_base<char_type>::preferred_separator;
#endif

// 30.10.8 class path


#ifdef GHC_OS_WINDOWS
class path;
namespace detail {
bool has_executable_extension(const path& p);
}
#endif


// 30.10.8 class path
class GHC_FS_API_CLASS path
#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_WSTRING_STRING_TYPE)
#define GHC_USE_WCHAR_T
Expand Down Expand Up @@ -442,9 +451,11 @@ class GHC_FS_API_CLASS path
};
friend void swap(path& lhs, path& rhs) noexcept;
friend size_t hash_value(const path& p) noexcept;
string_type::size_type root_name_length() const noexcept;
static void postprocess_path_with_format(impl_string_type& p, format fmt);
impl_string_type _path;
#ifdef GHC_OS_WINDOWS
friend bool detail::has_executable_extension(const path& p);
impl_string_type native_impl() const;
mutable string_type _native_cache;
#else
Expand Down Expand Up @@ -1607,6 +1618,11 @@ GHC_INLINE bool startsWith(const std::string& what, const std::string& with)
return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin());
}

GHC_INLINE bool endsWith(const std::string& what, const std::string& with)
{
return with.length() <= what.length() && what.compare(what.length() - with.length(), with.size(), with);
}

} // namespace detail

GHC_INLINE void path::postprocess_path_with_format(path::impl_string_type& p, path::format fmt)
Expand Down Expand Up @@ -1996,7 +2012,7 @@ GHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(const BY_H
}

template <typename INFO>
GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code&, uintmax_t* sz = nullptr, time_t* lwt = nullptr) noexcept
GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code&, uintmax_t* sz = nullptr, time_t* lwt = nullptr)
{
file_type ft = file_type::unknown;
if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
Expand All @@ -2014,8 +2030,7 @@ GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::er
if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
prms = prms | perms::owner_write | perms::group_write | perms::others_write;
}
std::string ext = p.extension().generic_string();
if (equals_simple_insensitive(ext.c_str(), ".exe") || equals_simple_insensitive(ext.c_str(), ".cmd") || equals_simple_insensitive(ext.c_str(), ".bat") || equals_simple_insensitive(ext.c_str(), ".com")) {
if (has_executable_extension(p)) {
prms = prms | perms::owner_exec | perms::group_exec | perms::others_exec;
}
if (sz) {
Expand Down Expand Up @@ -2659,43 +2674,47 @@ GHC_INLINE int path::compare(const value_type* s) const

//-----------------------------------------------------------------------------
// 30.10.8.4.9, decomposition
GHC_INLINE path path::root_name() const
GHC_INLINE path::string_type::size_type path::root_name_length() const noexcept
{
#ifdef GHC_OS_WINDOWS
if (_path.length() >= 2 && std::toupper(static_cast<unsigned char>(_path[0])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[0])) <= 'Z' && _path[1] == ':') {
return path(_path.substr(0, 2));
return 2;
}
#endif
if (_path.length() > 2 && _path[0] == '/' && _path[1] == '/' && _path[2] != '/' && std::isprint(_path[2])) {
impl_string_type::size_type pos = _path.find_first_of("/\\", 3);
if (pos == impl_string_type::npos) {
return path(_path);
return _path.length();
}
else {
return path(_path.substr(0, pos));
return pos;
}
}
return path();
return 0;
}

GHC_INLINE path path::root_name() const
{
return path(_path.substr(0, root_name_length()), generic_format);
}

GHC_INLINE path path::root_directory() const
{
path root = root_name();
if (_path.length() > root._path.length() && _path[root._path.length()] == '/') {
return path("/");
if(has_root_directory()) {
return path("/", generic_format);
}
return path();
}

GHC_INLINE path path::root_path() const
{
return root_name().generic_string() + root_directory().generic_string();
return path(root_name().generic_string() + root_directory().generic_string(), generic_format);
}

GHC_INLINE path path::relative_path() const
{
std::string root = root_path()._path;
return path(_path.substr((std::min)(root.length(), _path.length())), generic_format);
auto rootPathLen = root_name_length() + (has_root_directory() ? 1 : 0);
return path(_path.substr((std::min)(rootPathLen, _path.length())), generic_format);
}

GHC_INLINE path path::parent_path() const
Expand Down Expand Up @@ -2732,24 +2751,48 @@ GHC_INLINE path path::stem() const
{
impl_string_type fn = filename().string();
if (fn != "." && fn != "..") {
impl_string_type::size_type n = fn.rfind('.');
if (n != impl_string_type::npos && n != 0) {
return path{fn.substr(0, n)};
impl_string_type::size_type pos = fn.rfind('.');
if (pos != impl_string_type::npos && pos > 0) {
return path{fn.substr(0, pos), generic_format};
}
}
return path{fn};
return path{fn, generic_format};
}

GHC_INLINE path path::extension() const
{
impl_string_type fn = filename().string();
impl_string_type::size_type pos = fn.find_last_of('.');
if (pos == std::string::npos || pos == 0) {
return "";
if (has_relative_path()) {
auto iter = end();
const auto& fn = *--iter;
impl_string_type::size_type pos = fn._path.rfind('.');
if (pos != std::string::npos && pos > 0) {
return path(fn._path.substr(pos), generic_format);
}
}
return fn.substr(pos);
return path();
}

#ifdef GHC_OS_WINDOWS
namespace detail {
GHC_INLINE bool has_executable_extension(const path& p)
{
if (p.has_relative_path()) {
auto iter = p.end();
const auto& fn = *--iter;
auto pos = fn._path.find_last_of('.');
if (pos == std::string::npos || pos == 0 || fn._path.length() - pos != 3) {
return false;
}
const char* ext = fn._path.c_str() + pos + 1;
if (detail::equals_simple_insensitive(ext, "exe") || detail::equals_simple_insensitive(ext, "cmd") || detail::equals_simple_insensitive(ext, "bat") || detail::equals_simple_insensitive(ext, "com")) {
return true;
}
}
return false;
}
} // namespace detail
#endif

//-----------------------------------------------------------------------------
// 30.10.8.4.10, query
GHC_INLINE bool path::empty() const noexcept
Expand All @@ -2759,22 +2802,24 @@ GHC_INLINE bool path::empty() const noexcept

GHC_INLINE bool path::has_root_name() const
{
return !root_name().empty();
return root_name_length() > 0;
}

GHC_INLINE bool path::has_root_directory() const
{
return !root_directory().empty();
auto rootLen = root_name_length();
return (_path.length() > rootLen && _path[rootLen] == '/');
}

GHC_INLINE bool path::has_root_path() const
{
return !root_path().empty();
return has_root_name() || has_root_directory();
}

GHC_INLINE bool path::has_relative_path() const
{
return !relative_path().empty();
auto rootPathLen = root_name_length() + (has_root_directory() ? 1 : 0);
return rootPathLen < _path.length();
}

GHC_INLINE bool path::has_parent_path() const
Expand All @@ -2784,7 +2829,7 @@ GHC_INLINE bool path::has_parent_path() const

GHC_INLINE bool path::has_filename() const
{
return !filename().empty();
return has_relative_path() && !filename().empty();
}

GHC_INLINE bool path::has_stem() const
Expand Down

0 comments on commit c8cfcf8

Please sign in to comment.