Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Changeset 3764

Show
Ignore:
Timestamp:
07/20/08 07:31:09 (5 months ago)
Author:
larsivi
Message:

Remove heap churn, make it possible to use optional buffer

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/tango/util/PathUtil.d

    r3763 r3764  
    1616 
    1717private import  tango.core.Exception; 
     18 
     19private extern (C) void memmove (void* dst, void* src, uint bytes); 
    1820 
    1921/******************************************************************************* 
     
    3436    be fully normalized. 
    3537 
     38    The input path is copied into either the provided buffer, or a heap 
     39    allocated array if no buffer was provided. Normalization modifies 
     40    this copy before returning the relevant slice. 
     41 
    3642    Throws: IllegalArgumentException if the root separator is followed by .. 
    3743 
     
    4349*******************************************************************************/ 
    4450 
    45 char[] normalize(char[] path
    46 { 
    47  
     51char[] normalize(char[] path, char[] buf = null
     52{ 
     53    uint end; 
    4854version (Windows) { 
    4955    /* 
     
    6066    } 
    6167} 
     68    /* 
     69       Internal helper to truncate the path, avoids heap usage. 
     70    */ 
     71    void truncate(char[] path, char[] slice1, char[] slice2) { 
     72        memmove(path.ptr, slice1.ptr, slice1.length); 
     73        memmove(path.ptr + slice1.length, slice2.ptr, slice2.length); 
     74        assert (end > slice1.length+slice2.length); 
     75        end = slice1.length+slice2.length; 
     76    } 
    6277 
    6378    /* 
     
    6580    */ 
    6681    int findSlashDot(char[] path, int start) { 
    67         assert(start < path.length); 
    68         foreach(i, c; path[start..$-1])  
     82        assert(start < end); 
     83        foreach(i, c; path[start..end-1])  
    6984            if (c == '/')  
    7085                if (path[start+i+1] == '.')  
     
    7893    */ 
    7994    int findSlash(char[] path, int start) { 
    80         assert(start < path.length); 
     95        assert(start < end); 
    8196 
    8297        if (start < 0) 
     
    94109        Internal helper that recursively shortens all segments with dots. 
    95110    */ 
    96     char[] removeDots(char[] path, int start) { 
    97         assert (start < path.length); 
     111    void removeDots(char[] path, int start) { 
     112        assert (start < end); 
    98113        assert (path[start] == '.'); 
    99         if (start + 1 == path.length) { 
     114        if (start + 1 == end) { 
    100115            // path ends with /., remove 
    101             return path[0..start - 1]; 
     116            end = start - 1; 
     117            return; 
    102118        } 
    103119        else if (path[start+1] == '/') { 
    104120            // remove all subsequent './' 
    105121            do { 
    106                 path = path[0..start] ~ path[start+2..$]
    107             } while (start + 2 < path.length && path[start..start+2] == "./"); 
     122                truncate(path, path[0..start], path[start+2..end])
     123            } while (start + 2 < end && path[start..start+2] == "./"); 
    108124            int idx = findSlashDot(path, start - 1); 
    109125            if (idx < 0) { 
    110126                // no more /., return path 
    111                 return path
     127                return
    112128            } 
    113129            return removeDots(path, idx); 
     
    127143} 
    128144            int idx = findSlash(path, start - 2); 
    129             if (start + 2 == path.length) { 
     145            if (start + 2 == end) { 
    130146                // path ends with /.. 
    131147                if (idx < 0) { 
    132148                    // no more slashes in front of /.., resolves to empty path 
    133                     return ""; 
     149                    end = 0; 
     150                    return; 
    134151                } 
    135152                // remove /.. and preceding segment and return 
    136                 return path[0..idx]; 
     153                end = idx; 
     154                return; 
    137155            } 
    138156            else if (path[start+2] == '/') { 
     
    145163                    if (idx < 0) { 
    146164                        // no more /., path fully shortened 
    147                         return path
     165                        return
    148166                    } 
    149167                    return removeDots(path, idx); 
    150168                } 
    151                 path = path[0..idx < 0 ? 0 : idx + 1] ~ path[start+3..$]
     169                truncate(path, path[0..idx < 0 ? 0 : idx + 1], path[start+3..end])
    152170                idx = findSlashDot(path, idx < 0 ? 0 : idx); 
    153171                if (idx < 0) { 
    154172                    // no more /., path fully shortened 
    155                     return path
     173                    return
    156174                } 
    157175                // examine next /. 
     
    160178        } 
    161179        else { 
    162             if (findSlash(path, path.length - 1) < start) 
     180            if (findSlash(path, end - 1) < start) 
    163181                // segment is filename that starts with ., and at the end 
    164                 return path
     182                return
    165183            else { 
    166184                // not at end 
     
    169187                    return removeDots(path, idx); 
    170188                else 
    171                     return path
     189                    return
    172190            } 
    173191        } 
     
    178196        return path; 
    179197 
    180     char[] normpath = path.dup; 
     198    char[] normpath; 
     199    if (buf is null) { 
     200        normpath = path.dup; 
     201    } 
     202    else { 
     203        normpath = buf;  
     204        normpath[0..path.length] = path; 
     205    } 
     206 
    181207version (Windows) { 
    182208    normpath = normalizeSlashes(normpath); 
    183209} 
     210    end = normpath.length; 
    184211 
    185212    // if path starts with ./, remove all subsequent instances 
    186     while (normpath.length > 1 && normpath[0] == '.' && 
    187         normpath[1] == '/') { 
    188         normpath = normpath[2..$]; 
     213    while (end > 1 && normpath[0] == '.' && normpath[1] == '/') { 
     214        truncate(normpath, normpath[0..0], normpath[2..end]); 
    189215    } 
    190216    int idx = findSlashDot(normpath, 0); 
    191217    if (idx > -1) { 
    192         normpath = removeDots(normpath, idx); 
    193     } 
    194  
    195     return normpath
     218        removeDots(normpath, idx); 
     219    } 
     220 
     221    return normpath[0..end]
    196222} 
    197223 
     
    203229    { 
    204230        assert (normalize ("") == ""); 
    205         assert (normalize ("/home/../john/../.tango/.htaccess") == "/.tango/.htaccess", 
    206                 normalize ("/home/../john/../.tango/.htaccess")); 
    207         assert (normalize ("/home/../john/../.tango/foo.conf") == "/.tango/foo.conf", 
    208                 normalize ("/home/../john/../.tango/foo.conf")); 
    209         assert (normalize ("/home/john/.tango/foo.conf") == "/home/john/.tango/foo.conf", 
    210                 normalize ("/home/john/.tango/foo.conf")); 
    211         assert (normalize ("/foo/bar/.htaccess") == "/foo/bar/.htaccess",  
    212                 normalize ("/foo/bar/.htaccess")); 
    213         assert (normalize ("foo/bar/././.") == "foo/bar",  
    214                 normalize ("foo/bar/././.")); 
    215         assert (normalize ("././foo/././././bar") == "foo/bar",  
    216                 normalize ("././foo/././././bar")); 
    217         assert (normalize ("/foo/../john") == "/john",  
    218                 normalize("/foo/../john")); 
     231        assert (normalize ("/home/../john/../.tango/.htaccess") == "/.tango/.htaccess"); 
     232        assert (normalize ("/home/../john/../.tango/foo.conf") == "/.tango/foo.conf"); 
     233        assert (normalize ("/home/john/.tango/foo.conf") == "/home/john/.tango/foo.conf"); 
     234        assert (normalize ("/foo/bar/.htaccess") == "/foo/bar/.htaccess"); 
     235        assert (normalize ("foo/bar/././.") == "foo/bar"); 
     236        assert (normalize ("././foo/././././bar") == "foo/bar"); 
     237        assert (normalize ("/foo/../john") == "/john"); 
    219238        assert (normalize ("foo/../john") == "john"); 
    220239        assert (normalize ("foo/bar/..") == "foo");