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 }