Skip to content

Commit 5370bb4

Browse files
committed
Speed up splitExtension
1 parent faac262 commit 5370bb4

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

System/FilePath/Internal.hs

+17-6
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,24 @@ getSearchPath = fmap splitSearchPath (getEnv "PATH")
290290
-- > splitExtension "file.txt/boris.ext" == ("file.txt/boris",".ext")
291291
-- > splitExtension "file/path.txt.bob.fred" == ("file/path.txt.bob",".fred")
292292
-- > splitExtension "file/path.txt/" == ("file/path.txt/","")
293+
294+
-- A naive implementation would be to use @splitFileName_@ first,
295+
-- then break filename into basename and extension, then recombine dir and basename.
296+
-- This is way too expensive, see @splitFileName_@ comment for discussion.
297+
--
298+
-- Instead we speculatively split on the extension separator first, then check
299+
-- whether results are well-formed.
293300
splitExtension :: FILEPATH -> (STRING, STRING)
294-
splitExtension x = if null nameDot
295-
then (x, mempty)
296-
else (dir <> init nameDot, extSeparator `cons` ext)
297-
where
298-
(dir,file) = splitFileName_ x
299-
(nameDot,ext) = breakEnd isExtSeparator file
301+
splitExtension x
302+
-- Imagine x = "no-dots", then nameDot = ""
303+
| null nameDot = (x, mempty)
304+
-- Imagine x = "\\shared.with.dots\no-dots"
305+
| isWindows && null (dropDrive nameDot) = (x, mempty)
306+
-- Imagine x = "dir.with.dots/no-dots"
307+
| any isPathSeparator ext = (x, mempty)
308+
| otherwise = (init nameDot, extSeparator `cons` ext)
309+
where
310+
(nameDot, ext) = breakEnd isExtSeparator x
300311

301312
-- | Get the extension of a file, returns @\"\"@ for no extension, @.ext@ otherwise.
302313
--

0 commit comments

Comments
 (0)