Mercurial > public > mercurial-scm > hg
comparison mercurial/pathencode.c @ 17606:318fb32b980e
pathencode: new C module with fast encodedir() function
Not yet used (will be enabled in a later patch).
This patch is a stripped down version of patches originally created by
Bryan O'Sullivan <bryano@fb.com>
author | Adrian Buehlmann <adrian@cadifra.com> |
---|---|
date | Tue, 18 Sep 2012 11:43:30 +0200 |
parents | |
children | 9535a0dc41f2 |
comparison
equal
deleted
inserted
replaced
17605:e9cc29be3305 | 17606:318fb32b980e |
---|---|
1 /* | |
2 pathencode.c - efficient path name encoding | |
3 | |
4 Copyright 2012 Facebook | |
5 | |
6 This software may be used and distributed according to the terms of | |
7 the GNU General Public License, incorporated herein by reference. | |
8 */ | |
9 | |
10 #include <Python.h> | |
11 #include <assert.h> | |
12 #include <ctype.h> | |
13 #include <stdlib.h> | |
14 #include <string.h> | |
15 | |
16 #include "util.h" | |
17 | |
18 /* state machine for dir-encoding */ | |
19 enum dir_state { | |
20 DDOT, | |
21 DH, | |
22 DHGDI, | |
23 DDEFAULT, | |
24 }; | |
25 | |
26 static inline void charcopy(char *dest, Py_ssize_t *destlen, size_t destsize, | |
27 char c) | |
28 { | |
29 if (dest) { | |
30 assert(*destlen < destsize); | |
31 dest[*destlen] = c; | |
32 } | |
33 (*destlen)++; | |
34 } | |
35 | |
36 static inline void memcopy(char *dest, Py_ssize_t *destlen, size_t destsize, | |
37 const void *src, Py_ssize_t len) | |
38 { | |
39 if (dest) { | |
40 assert(*destlen + len < destsize); | |
41 memcpy((void *)&dest[*destlen], src, len); | |
42 } | |
43 *destlen += len; | |
44 } | |
45 | |
46 static Py_ssize_t _encodedir(char *dest, size_t destsize, | |
47 const char *src, Py_ssize_t len) | |
48 { | |
49 enum dir_state state = DDEFAULT; | |
50 Py_ssize_t i = 0, destlen = 0; | |
51 | |
52 while (i < len) { | |
53 switch (state) { | |
54 case DDOT: | |
55 switch (src[i]) { | |
56 case 'd': | |
57 case 'i': | |
58 state = DHGDI; | |
59 charcopy(dest, &destlen, destsize, src[i++]); | |
60 break; | |
61 case 'h': | |
62 state = DH; | |
63 charcopy(dest, &destlen, destsize, src[i++]); | |
64 break; | |
65 default: | |
66 state = DDEFAULT; | |
67 break; | |
68 } | |
69 break; | |
70 case DH: | |
71 if (src[i] == 'g') { | |
72 state = DHGDI; | |
73 charcopy(dest, &destlen, destsize, src[i++]); | |
74 } | |
75 else state = DDEFAULT; | |
76 break; | |
77 case DHGDI: | |
78 if (src[i] == '/') { | |
79 memcopy(dest, &destlen, destsize, ".hg", 3); | |
80 charcopy(dest, &destlen, destsize, src[i++]); | |
81 } | |
82 state = DDEFAULT; | |
83 break; | |
84 case DDEFAULT: | |
85 if (src[i] == '.') | |
86 state = DDOT; | |
87 charcopy(dest, &destlen, destsize, src[i++]); | |
88 break; | |
89 } | |
90 } | |
91 | |
92 return destlen; | |
93 } | |
94 | |
95 PyObject *encodedir(PyObject *self, PyObject *args) | |
96 { | |
97 Py_ssize_t len, newlen; | |
98 PyObject *pathobj, *newobj; | |
99 char *path; | |
100 | |
101 if (!PyArg_ParseTuple(args, "O:encodedir", &pathobj)) | |
102 return NULL; | |
103 | |
104 if (PyString_AsStringAndSize(pathobj, &path, &len) == -1) { | |
105 PyErr_SetString(PyExc_TypeError, "expected a string"); | |
106 return NULL; | |
107 } | |
108 | |
109 newlen = len ? _encodedir(NULL, 0, path, len + 1) : 1; | |
110 | |
111 if (newlen == len + 1) { | |
112 Py_INCREF(pathobj); | |
113 return pathobj; | |
114 } | |
115 | |
116 newobj = PyString_FromStringAndSize(NULL, newlen); | |
117 | |
118 if (newobj) { | |
119 PyString_GET_SIZE(newobj)--; | |
120 _encodedir(PyString_AS_STRING(newobj), newlen, path, | |
121 len + 1); | |
122 } | |
123 | |
124 return newobj; | |
125 } |