以前写了一个,也贴出来了不过对模版支持不好,不带模版的函数和类成员函数还是支持的。
最近写模版类的头文件,而模版类的话如果不想inline在外部实现的化,书写起来格式很麻烦。尤其是如果返回变量的类型是在类内部typedef的类型。
所以对以前的程序修改了以下,还是利用Python正则表示生成对应的实现文件,对于模版类其实也可以生产.cc文件的将函数的实现写在.cc文件中,
如在MeshT.h文件的最后include的实现文件MeshT.cc就可以了(Openmesh就是这么做的,下面有例子),
这样避免代码都写在.h中比较乱,而且头文件太长。
嗯,现在的h2cc.py基本能完成要求,可能有些特殊情况会出问题,待验证,另外代码有多个地方重复的地方待整理。
下一步要做的,
1.进一步测试对各种情况正确无误,包括更复杂的模版测试,
2.当前完全按照格式处理,不考虑语义理解,所以对于SGI STL源代码那样头文件中把函数返回变量单独写一行的无法处理。这个以后有好的办法再处理。
(感觉做编译器的完全能写个.h到.cc的自动转换工具为啥我搜不到呢,还得自己写....肯定不如人家的精确)
3. 当前如果存在生成文件了已经,比如用户开始生成了.cc然后又在.h中增加方法,再次生成.cc的时候我会将新的方法统一写在原来.cc文件的最后,具体合适
的位置用户再改动。 下一步考虑自动将新的方法插入到原来.cc文件的合适位置,不过用户如果改动如函数格式,nameapce名称,新添加namespace等等肯定会带来问题
那个用户自己处理吧(注意这里的.cc文件都是按照h2cc.py生成)
4.像java或者python那样,将所有的代码都写到一起,即不存在头文件的写法,这样代码写起来更方便。对于C++代码可以全部写到.h中。然后调用转换
工具,自动生成.cc文件,将所有没有声明inline的函数并且实现代码长度超过n行的(如10行)自动在.h中转换为声明格式,在.cc中写成实现格式
并把实现代码拷贝过去,
可以用户紧挨函数在上面一行开头加注释如//*标明下面的函数不做转换处理在.h中inline。
个人觉得这样还是能提高写程序的效率的,不知道现在有没有现成的转换工具。
5.要做上面的工作需要对代码修改,当前的代码可扩充性太差....,扩展功能麻烦,首先把各个重复的地方提前出来统一处理。如去掉=的模式。
试图写子函数,但是问题是我需要对每一行代码做太多的情形分析,这样while循环太长了,又不好分子程序,
尤其是 python不支持类似c++的引用,写子函数修改输入变量如输入行号i并在子函数中修改,用Python还得返回i才行,别扭:(
嗯,最后决定暂时就这样了,程序不改了,当前的做法对于{}的处理采用统一忽略的做法包括类似if abc() {}的处理,修改实现其它的功能比较麻烦。。。
//h2cc.py
1 #!/usr/local/bin/python3.1
2
#
file h2cc.py
3
#
author [email protected]
4
#
date 2009-10-23 18:19:38.970028
5
6
#
.h convert to .cpp framework
7
#
注意!!
8
#
1. 我们假定你的.h代码书写正确 当前不做异常,错误处理
9
#
2. 函数的返回类型如 int 与 与函数名称要写到一行,否则会有问题,因为不太好判断函数名称.
10
#
3. 如果已经存在要生成的文件,会只写入你在.h中新加入的函数,
11
#
但是注意原来已经存在的实现文件也应该是用h2cc.py生成的,因为我不是按语意判断,只是按照格式判断
12
#
新写的实现函数框架,会附加到原来的生成文件最后面,需要自己调整到需要的位置,尤其是有namespace的时候
13
#
TODO 新写的函数直接放到原来生成文件中适当的位置
14
#
4. 在生成的实现文件中,可能会把返回值单独一行,取决于行的长度,过长则分行
15
#
5. 如果template模板写成多行,确保最后一行只有一个单独的>
16
#
template <
17
#
typename T = char,
18
#
template<typename> class _Decoder = HuffDecoder<int> #pattern like this might cause error
19
#
>
20
21
22
#
在某行发现) ; 之后,删除该行;之后的内容,该行开始的空白去掉
23
#
改为 \n\{\n\}
24
#
virtual = 0 对于纯虚函数也生成实体,如不需要自己去掉. TODO 用户选项
25
#
TODO 允许向SGI STL源代码那样,将返回值单独一行,在函数名称上面,不过似乎比较困难,因为当前
26
#
我的程序基本按照(){};template class typdef define // /* */识别这些字符的,仅仅考虑格式
27
#
不考虑语意如果返回值
28
#
单独一行,如何判断什么样的是返回值类型呢?比较麻烦.比如还要区分仅仅挨着占两行的两个函数声明.
29
30
#
最常用的pattern
31
#
查找如下 ) ; 或者 ) const ; 但是不包括纯虚函数
32
#
()z中如找到 ; //从队尾删除
33
#
开始的空白要找到并删除,
34
#
pattern = re.compile(r"([\s]*?).*[)](?!\s*=\s*0).*(;.*)\n$")
35
36
#
class A : public 读出A未解决 done
37
#
template done 支持模板类,模板函数,带有默认参数的模板,模板类中的模板函数,特化和偏特化
38
#
TODO 更复杂的情况可能有问题,比如模板类中嵌套模板类
39
#
vitrual = 0 done
40
#
支持 const done
41
#
宏 DFDFDFEE(ABC); done
42
#
把注释拷贝 done
43
#
已经有.cpp了 仅仅加新的接口的实现 partly done
44
#
忽略返回类型,返回类型不能重载
45
#
operator done
46
47
import
sys,re,getopt
48
49
def
usage():
50
"""
51
Run the program like this
52
53
./h2cc.py abc.h ok.cc
54
It will read abc.h and append the fuctions
55
to be implemented to ok.cc
56
57
or
58
./h2cc.py abc.h #will create abc.cc
59
./h2cc.py abc.h cpp #will create abc.cpp
60
"""
61
pattern_comment
=
re.compile(r
'
^\s*//
'
)
62
63
#
传入一个打开的文件(我们要生成的或者已经存在要分析处理)的handle,如abc.cc
64
#
调用该函数者负责关闭该文件,该函数只负责处理
65
func_list_exist
=
[]
66
def
AnalyzeOutputFile(file_handle):
67
print
(
'
Analyze output file right now ,the reslt of existing functions is below\n
'
)
68
file_handle.seek(0,0)
69
m
=
file_handle.readlines()
70
i
=
0
71
#
---------------------------------------------------逐行处理
72
while
(i
<
len(m)):
73
line
=
m[i]
74
#
---------------------判断是注释则略过 re.search(r'^s*$',line) 空行判断
75
if
re.search(r
'
^s*$
'
,line)
or
pattern_comment.search(line):
#
null line or comment using //
76
i
+=
1
77
continue
78
if
re.search(
'
^\s*/[*]
'
, line):
#
comment using /*
79
while
(
not
re.search(
'
[*]/\s*$
'
,line)):
#
*/
80
i
+=
1
81
line
=
m[i]
82
i
+=
1
83
continue
84
#
-------------------------find exists functions
85
find1
=
re.search(
'
[(]
'
,line)
86
find2
=
re.search(
'
[)]
'
,line)
87
find3
=
re.search(
'
template
'
,line)
88
find4
=
re.search(
'
::
'
,line)
89
if
((find1
or
find3
or
find4)
and
(
not
find2)):
90
i
+=
1
91
line
+=
m[i]
92
while
(i
<
len(m)
and
(
not
re.search(
'
[)]
'
,line))):
93
i
+=
1
94
line
+=
m[i]
95
match
=
re.search(
'
^.*\)
'
,line,re.MULTILINE
|
re.DOTALL)
96
if
match:
97
print
(match.group())
98
func_list_exist.append(match.group())
99
i
+=
1
100
print
(
'
Output file analze done!
'
)
101
print
(
'
There are already %d functions exit\n
'
%
len(func_list_exist))
102
103
#
转化核心函数,当前比较乱,代码重复,一个循环中代码太长了 TODO
104
#
基本实现就是按照栈处理名称,区分是否class域的函数,忽略.h中已经实现函数{}内部的内容
105
def
h2cc(input_file,output_file):
106
"""
107
kernal function given a .h file
108
convert to a .cc one with
109
all the functions properly listed
110
"""
111
print
(
'
The file you want to deal with is
'
+
input_file
+
\
112
'
\n It is converted to
'
+
output_file)
113
114
#
----核心的函数匹配模式
115
pattern
=
re.compile(r
"""
(^[\s]*) #leading withe space,we will find and delete after
116
([a-zA-Z~_] # void int likely the first caracter v or i
117
.*
118
[)] #we find )
119
#(?!\s*=\s*0) #if we find = 0 which means pur virtual we will not match after
120
#(?=\s*=\s*0)
121
(?!.*{) # we do not want the case int abc() const { return 1;}
122
.*)
123
(;.*) #we want to find ; and after for we will replace these later
124
\n$
125
"""
,re.VERBOSE
|
re.MULTILINE
|
re.DOTALL)
126
127
#
----处理virtual,explicit,friend,static
128
pattern2
=
re.compile(r
'
(virtual\s+|explicit\s+|friend\s+|static\s+)
'
)
129
130
#
----开头的空白
131
leading_space_pattern
=
re.compile(
'
(^[\s]*)[a-zA-Z~]
'
)
132
133
#
我们默认函数都会有 如 abc( abc ( 这样的模式存在
134
#
但是operator 是个例外,类名要加在operaotr前面,而且不存在上面的模式
135
#
operator = () ClassName::operator = ()
136
#
pattern_func_name = re.compile(r'([a-zA-Z0-9~_\-]+\s*[(]|operator.*[(])')
137
#
难道替换不是仅仅替换括号里面的 而是全部替换? 恩,大括号 必须的 然后用\1没有\0
138
pattern_func_name
=
re.compile(r
'
([a-zA-Z0-9~_\-]+\s*|operator.*)[(]
'
)
139
140
pattern_template
=
re.compile(
'
^\s*template
'
)
141
#
pattern_template_end = re.compile('^\s*>\s*$') #TODO why wrong?
142
pattern_template_end
=
re.compile(
'
>\s*$
'
)
143
144
pattern_namespace
=
re.compile(r
'
namespace.*{
'
)
#
判断该行是否是 namespace出现
145
#
p2 = re.compile(r'class\s*(.*?)\s*{|struct\s*(.*?)\s*{')
146
#
.*? 最小匹配 是否class出现,并记录class 名称
147
pattern_class
=
re.compile(r
'
^[\s]*(class|struct)\s+([a-zA-Z0-9_\-]+<?)(?!.*;)
'
)
148
#
modify 09.6.6 可以处理classa a 和 { 不在同一行,但是如果class 后发现;不处理
149
#
class一定是行开始或者前面可有空白
150
151
pattern_start
=
re.compile(
'
{
'
)
152
pattern_end
=
re.compile(
'
}
'
)
153
154
stack
=
[]
#
----状态可能是normal_now(位于{}中间的时候),class_now,namespace_now
155
stack_class
=
[]
#
----存储class name
156
stack_template
=
[]
#
----存储template name
157
stack_typedef
=
[]
#
----存储当前class 作用域下的所有typedef得到的名称,函数返回类型需要
158
159
first_convert
=
True
#
是否是第一次生成的实现文件
160
161
#
--------------------------------------文件处理
162
try
:
#
09.6.6 处理要转换生成的.cc 或 .cpp文件不存在的情况,添加读异常
163
f_out
=
open(output_file,
'
r+
'
)
#
r+ 可读写但要求文件已经存在
164
print
(output_file
+
'
exists already, we will anlyze it to find the existing functions to avoid adding twice
'
)
165
AnalyzeOutputFile(f_out)
#
对输出文件进行预处理分析
166
first_convert
=
False
167
except
IOError:
168
print
(output_file
+
'
does not exist yet, we will create am empty
'
+
output_file)
169
f_out
=
open(output_file,
'
a
'
)
#
追加打开,这里因为用了异常先判断了是否文件存在,所以也可以用 w
170
#
如果没有前面的判断只能用 a ,w 会自动删除前面已有的内容
171
print
(
'
Below functions will be added\n
'
)
172
if
first_convert:
173
f_out.write(
'
#include "
'
+
input_file
+
'
"\n\n
'
)
#
注意 如果out文件已存在 那么经过前面的分析处理 指针已经指向了文件尾部
174
175
func_sum
=
0
176
#
--------------------------------------------------核心处理循环,逐行处理输入.h文件
177
with open(input_file,
'
r
'
) as f:
178
m
=
f.readlines()
179
i
=
0
180
while
i
<
len(m):
181
line
=
m[i]
182
#
-------------------------------------------判断是注释则略过 re.search(r'^s*$',line) 空行判断
183
if
re.search(r
'
^s*$
'
,line)
or
pattern_comment.search(line):
#
/n or comment using //
184
i
+=
1
185
continue
186
if
re.search(
'
^\s*/[*]
'
, line):
#
comment using /*
187
while
(
not
re.search(
'
[*]/\s*$
'
,line)):
#
*/
188
i
+=
1
189
line
=
m[i]
190
i
+=
1
191
continue
192
#
---------------------------------------------判断是则define略过
193
define_match
=
re.search(r
'
^\s*#define
'
,line)
194
if
define_match:
195
while
re.search(r
'
^\s*$
'
,line)
or
re.search(r
'
\\\s*$
'
, line):
196
i
+=
1
197
line
=
m[i]
198
i
+=
1
199
continue
200
#
-----------------------------------------------判断是否namespace
201
match_namespace
=
pattern_namespace.search(line)
202
if
match_namespace:
#
we face namespace
203
if
first_convert:
204
f_out.write(line
+
'
\n
'
)
205
stack.append(
'
namespace_now
'
)
206
i
+=
1
207
continue
208
#
----------------------------------------------------判断并处理类里面的typedef
209
if
(len(stack)
>
0
and
stack[
-
1
]
==
'
class_now
'
):
210
pattern_typedef
=
re.compile(r
'
typedef\s+.*\s+(.*);
'
)
211
match_typedef
=
pattern_typedef.search(line)
212
if
match_typedef:
213
stack_typedef.append(match_typedef.group(
1
))
214
#
----------------------------------------------------判断并处理模板情况
215
match_template
=
pattern_template.search(line)
216
template_string
=
''
217
if
match_template:
218
match_template_end
=
pattern_template_end.search(line)
219
template_string
=
line
220
while
(
not
match_template_end):
221
i
+=
1
222
line
=
m[i]
223
template_string
+=
line
224
match_template_end
=
pattern_template_end.search(line)
225
i
+=
1
226
line
=
m[i]
227
#
--------------------------------------------判断是否是class 或者遇到 { start
228
match_class
=
pattern_class.search(line)
229
match_start
=
pattern_start.search(line)
230
231
if
match_class:
#
we face a class
232
stack_template.append(template_string)
233
stack.append(
'
class_now
'
)
234
class_name
=
match_class.group(
2
)
#
TODO f2.group(1)如果为空则异常
235
#
-----------模板类特化或者偏特化的情况 如 class A<u,Node<u> > 为了获得整个名称
236
if
'
<
'
in
class_name:
237
k
=
line.index(
'
<
'
)
238
fit
=
1
;
239
for
l
in
range(k
+
1
, len(line)):
240
if
line[l]
==
'
<
'
:
241
fit
+=
1
242
if
line[l]
==
'
>
'
:
243
fit
-=
1
244
if
(fit
==
0):
245
break
246
class_name
+=
line[k
+
1
:l
+
1
]
247
stack_class.append(class_name)
248
while
not
match_start:
249
i
+=
1
250
line
=
m[i]
251
match_start
=
pattern_start.search(line)
252
i
+=
1
253
continue
254
#
-------------------------------------------------判断是否是结束符号 }
255
match_end
=
pattern_end.search(line)
256
if
match_start:
257
stack.append(
'
normal_now
'
)
258
if
match_end:
259
top_status
=
stack.pop()
260
if
top_status
==
'
namespace_now
'
:
261
if
first_convert:
262
f_out.write(line
+
'
\n
'
)
263
elif
top_status
==
'
class_now
'
:
264
stack_class.pop()
265
stack_template.pop()
266
stack_typedef
=
[]
267
if
match_start
or
match_end:
268
i
+=
1
269
continue
270
#
注意我判断是函数只是根据 我看到该行有) 然后 后面有; important!!
271
#
------------------------------------------------就像忽略注释一样忽略normal_now状态下的行,因为那是在{}中间的实现
272
if
len(stack)
>
0
and
stack[
-
1
]
==
'
normal_now
'
:
273
i
+=
1
274
continue
275
#
---------------------------------------------------------下面我们该处理需要生成实体框架的函数了,
276
#
deal with
277
#
int abc(int a,
278
#
int b) #能够处理这种(与)不在同一行的情况
279
find1
=
re.search(
'
[(]
'
,line)
280
if
not
find1:
281
i
+=
1
282
continue
283
find2
=
re.search(
'
[)]
'
,line)
284
start_i
=
i
285
if
(find1
and
(
not
find2)):
286
#
space = leading_space_pattern.search(line).group(1)
287
space_match
=
leading_space_pattern.search(line)
288
i
+=
1
289
line2
=
m[i]
290
if
space_match:
291
line2
=
re.sub(
'
^
'
+
space_match.group(
1
),
''
,line2)
292
#
注意sub会替换所有的匹配,这里我们只让它替换第一个,count=1,或者对于space 前面加^
293
line
+=
line2
294
while
(i
<
len(m)
and
(
not
re.search(
'
[)]
'
,line2))):
295
i
+=
1
296
line2
=
m[i]
297
line2
=
re.sub(
'
^
'
+
space_match.group(
1
),
''
,line2)
298
line
+=
line2
299
300
match_start
=
pattern_start.search(m[i])
301
match_end
=
pattern_end.search(m[i])
302
if
(match_start):
#
like ) { or ) {} int the last line
303
if
not
match_end:
304
stack.append(
'
normal_now
'
)
305
i
+=
1
306
continue
307
308
#
here we do the kernel sub #--------------------------------如果找到,先进行了替换abc();->abc{}
309
(line,match)
=
pattern.subn(r
'
\2 \n{\n\n}\n\n
'
,line)
310
if
(
not
match):
#
like abc() not ; after 就是说{在函数名下面单独一行的情况
311
i
+=
1
312
continue
313
314
#
-------------------------------------------------------------OK,找到了函数,下面进行处理后输出
315
if
match:
316
friend_match
=
re.search(
'
friend
'
,line)
317
line
=
pattern2.sub(
''
,line)
#
--------------------delete virtural explict friend!
318
func_name
=
''
319
template_line
=
''
320
if
len(stack_class)
>
0
and
not
friend_match :
#
-----类成员函数class status if friend we will not add class name
321
x
=
''
322
if
(template_string
!=
''
):
#
-----类中模板函数,多一个模板
323
template_string
=
re.sub(r
'
\s*template
'
,
'
template
'
,template_string)
324
#
template_string = re.sub(r'\s*=\s*[\'a-zA-Z0-9_\-\.]+', '', template_string)
325
#
------------------delete < class T = a, class U = A(3)> -> <class T, class U>
326
template_string
=
re.sub(
'
\s*=.*>(\s*)$
'
,r
'
>\1
'
,template_string)
327
template_string
=
re.sub(r
'
\s*=.*,
'
,
'
,
'
,template_string)
328
template_string
=
re.sub(r
'
\s*=.*
'
,
''
,template_string)
329
if
(stack_template[
-
1
]
!=
''
):
330
if
not
(re.search(r
'
<\s*>
'
, stack_template[
-
1
])):
#
----不是全特化!template<>
331
template_line
=
re.sub(r
'
^\s*template
'
,
'
template
'
,stack_template[
-
1
])
332
if
not
(re.search(r
'
<.*>
'
, stack_class[
-
1
])):
#
----不是偏特化!,like template<typename T> class A<T,int>
333
#
------for x we get like template<class T, typename U> -> <T,U>
334
x
=
re.sub(r
'
template\s*<
'
,
'
<
'
,template_line)
#
remove template -> <class T, typename U>
335
x
=
re.sub(r
'
\n
'
,
''
,x)
#
取消分行,合并成一行
336
#
去掉 = 及其后面的东西
337
x
=
re.sub(r
'
\s*=.*,
'
,
'
,
'
, x)
338
x
=
re.sub(r
'
\s*=.*\>
'
,
'
>
'
, x)
339
x
=
x.rstrip()
#
remove \n
340
x
=
re.sub(r
'
(class|typename)\s+|(<class>|<typename>\s*class)
'
,
''
,x)
#
去掉class,typename -> <T, U>
341
x
=
re.sub(r
'
<\s+
'
,
'
<
'
,x)
342
x
=
re.sub(r
'
\s+>
'
,
'
>
'
,x)
343
x
=
re.sub(r
'
\s+,
'
,
'
,
'
,x)
344
x
=
re.sub(r
'
,\s+
'
,
'
,
'
,x)
345
line
=
re.sub(r
'
\s*=\s*0
'
,
''
,line)
#
纯虚函数我们也给函数实现体,这里特别判断一下去掉 = 0
346
line
=
re.sub(r
'
\s*=.*,
'
,
'
,
'
, line)
#
去掉=后面的东西 foo(int a = cd(32));foo(int x =(3), int y= 4);
347
line
=
re.sub(r
'
\s*=.*\)
'
,
'
)
'
, line)
#
先去掉所有的(),最后去掉()),这两个步骤都需要不能颠倒
348
#
---------如果函数较长,在void ABC::foo() 断开成两行 void ABC::\n foo()
349
temp_line
=
pattern_func_name.sub(stack_class[
-
1
]
+
x
+
'
::
'
+
r
'
\1(
'
,line)
350
if
len(temp_line)
>
60
:
351
line
=
pattern_func_name.sub(stack_class[
-
1
]
+
x
+
'
::\n
'
+
r
'
\1(
'
,line)
352
else
:
353
line
=
temp_line
354
#
----------得到返回变量的类型
355
return_type
=
re.search(
'
^(\S+)
'
, line).group(
1
)
356
if
(return_type
in
stack_typedef):
#
------对于返回值,需要指明是在该类中typedef指定的名称的情况
357
if
(x
==
''
):
#
----全特化的情况特殊处理
358
line
=
re.sub(
'
^
'
+
return_type
+
r
'
\s+
'
, stack_class[
-
1
]
+
'
::
'
+
return_type
+
'
\\n
'
, line)
359
else
:
360
line
=
re.sub(
'
^
'
+
return_type
+
r
'
\s+
'
,
'
typename
'
+
stack_class[
-
1
]
+
'
::
'
+
return_type
+
'
\\n
'
, line)
361
#
----------add template as the above if there is one
362
#
template_line = re.sub(r'\s*=\s*[\'a-zA-Z0-9_\-\.]+', '', template_line)
363
#
------------------delete < class T = a, class U = A(3)> -> <class T, class U>
364
template_line
=
re.sub(
'
\s*=.*>(\s*)$
'
,r
'
>\1
'
,template_line)
365
template_line
=
re.sub(r
'
\s*=.*,
'
,
'
,
'
,template_line)
366
template_line
=
re.sub(r
'
\s*=.*
'
,
''
,template_line)
#
最后,不换行删除后面所有的
367
line
=
template_line
+
template_string
+
line;
368
func_name
=
re.search(
'
^.*\)
'
,line,re.MULTILINE
|
re.DOTALL).group()
369
else
:
#
--------------------------------普通函数(非类成员函数)的情况!
370
stack_template.append(template_string)
371
if
(stack_template[
-
1
]
!=
''
):
372
template_line
=
re.sub(r
'
\s*template
'
,
'
template
'
,stack_template[
-
1
])
373
#
template_line = re.sub(r'\s*=\s*[\'a-zA-Z0-9_\-\.]+', '', template_line)
374
#
------------------delete < class T = a, class U = A(3)> -> <class T, class U>
375
template_line
=
re.sub(
'
\s*=.*>(\s*)$
'
,r
'
>\1
'
,template_line)
#
代码重复,TODO以后整合
376
template_line
=
re.sub(r
'
\s*=.*,
'
,
'
,
'
,template_line)
377
template_line
=
re.sub(r
'
\s*=.*
'
,
''
,template_line)
378
line
=
re.sub(r
'
\s*=.*,
'
,
'
,
'
, line)
379
line
=
re.sub(r
'
\s*=.*\)
'
,
'
)
'
, line)
380
line
=
template_line
+
line
381
stack_template.pop()
382
func_name
=
re.search(
'
^.*\)
'
,line,re.MULTILINE
|
re.DOTALL).group()
383
#
-------------------------------------------------------------------------加上上面的注释也拷贝过去
384
comment_line
=
''
385
#
假定函数的注释在函数声明的紧上面,把他们拷贝过去
386
#
TODO 如果是模板函数,模板占多于1行注释没拷贝
387
k
=
start_i
-
1
#
one line befor this func start
388
if
pattern_template.search(m[k]):
389
k
-=
1
390
if
re.search(
'
[*]/\s*$
'
,m[k]):
391
comment_line
=
m[k].lstrip()
392
while
not
re.search(
'
^\s*/[*]
'
,m[k]):
393
k
-=
1
394
comment_line
=
m[k].lstrip()
+
comment_line
395
else
:
396
for
j
in
range(k,0,
-
1
):
397
c_line
=
m[j]
398
if
pattern_comment.search(c_line):
399
c_line
=
re.sub(
'
\s*//
'
,
'
//
'
,c_line)
#
TODO use strtip is ok?
400
comment_line
=
c_line
+
comment_line
401
else
:
402
break
403
line
=
comment_line
+
line
#
------------------我们最终要输出的东东
404
#
----------------------------------------------如果函数已经在实现文件中存在,不输出
405
if
not
(func_name
in
func_list_exist):
406
#
if not first_convert and func_sum == 0:
407
#
f_out.write("//newly added functions, you may need to move them to the right position\n")
408
f_out.write(line)
409
func_sum
+=
1
410
print
(func_name)
411
i
+=
1
#
-----------------------------------------------------------------------next line处理下一行
412
#
------------------------------loop done 处理结束
413
print
(
'
\nSucessfully converted,please see
'
+
output_file)
414
print
(
'
Added %d functions
'
%
func_sum)
415
416
417
#
-----------------------------------------------------------user input
418
def
main(argv):
419
try
:
420
opts, args
=
getopt.getopt(argv,
"
h
"
, [
"
help
"
])
421
except
getopt.GetoptError:
422
print
(usage.
__doc__
)
423
sys.exit(
2
)
424
425
if
len(opts)
>
0:
426
for
o, a
in
opts:
427
if
o
in
(
"
-h
"
,
"
--help
"
):
428
print
(usage.
__doc__
)
429
sys.exit()
430
elif
len(args)
>
0:
431
input_file
=
args[0]
432
if
len(args)
==
1
or
args[
1
]
==
'
cc
'
:
433
output_file
=
re.sub(
'
.h*$
'
,
'
.cc
'
,input_file)
#
默认转的是对应的.cc文件
434
elif
(args[
1
]
==
'
cpp
'
):
435
output_file
=
re.sub(
'
.h*$
'
,
'
.cpp
'
,input_file)
436
else
:
437
output_file
=
args[
1
]
438
439
h2cc(input_file,output_file)
440
else
:
441
print
(usage.
__doc__
)
442
sys.exit()
443
444
445
if
__name__
==
"
__main__
"
:
446
main(sys.argv[
1
:])
447
下面看一下常用的几种函数声明,其对应函数实现的写法,包括模版类函数,模版类中的模版函数等等。
1 /*演示函数定义的格式,主要演示在模版类外面定义成员函数的写法*/
2
#include
<
iostream
>
3
using
namespace
std;
4
5
int
abc(
int
x
=
3
,
int
y
=
4
);
6
7
template
<
typename T
>
8
struct
HuffDecoder {
9
10
};
11
template
<
12
typename T
=
char
,
13
template
<
typename
>
class
_Decoder
=
HuffDecoder
14
>
15
struct
Hand{
16
bool
operator
>
(
const
Hand
<
T,_Decoder
>&
other);
17
static
void
print();
18
};
19
20
template
<
typename T, template
<
typename
>
class
_Decoder
>
21
void
Hand
<
T, _Decoder
>
::print()
22
{
23
cout
<<
"
this is hand
"
<<
endl;
24
}
25
26
template
<
typename T
=
char
>
27
class
Foo {
28
public
:
29
typedef T Node;
30
typedef Hand
<
T
>
Handle;
31
typedef
int
size;
32
33
Handle foo(Node a);
34
35
//
Handle foo(Node a) {
36
//
cout << "haha" << endl;
37
//
}
38
39
//
static Handle foo2(Node a = 'a') {
40
//
cout << "haha" << endl;
41
//
}
42
static
Handle foo2(Node a
=
'
a
'
);
43
44
Hand
<
T
>
foo3();
45
46
template
<
typename U
>
47
void
swap(U x);
48
49
//
template <typename U>
50
//
class abc {
51
//
public:
52
//
static swap()
53
//
};
54
};
55
56
template
<
typename T
=
char
>
57
class
Derive :
public
Foo
<
T
>
58
{
59
public
:
60
typedef typename Foo
<
T
>
::size size;
61
static
void
print() {
62
size l
=
3333
;
63
cout
<<
l
<<
endl;
64
}
65
};
66
template
<>
67
class
Foo
<
int
>
68
{
69
public
:
70
typedef
int
Node;
71
typedef Hand
<
int
>
Handle;
72
Handle foo(Node a);
73
//
Handle foo(Node a) {
74
//
cout << "int foo" << endl;
75
//
}
76
77
};
78
79
template
<
typename T
>
80
class
Foo
<
T
*>
81
{
82
public
:
83
typedef Hand
<
int
>
Handle;
84
typedef
int
Node;
85
Handle foo(Node a);
86
};
87
88
template
<
typename T
>
89
typename Foo
<
T
*>
::Handle Foo
<
T
*>
::foo(Node a) {
90
cout
<<
"
T * foo
"
<<
endl;
91
}
92
93
//
template<>
94
//
typename Foo<int>::Handle Foo<int>::foo(Node a)
95
//
{
96
//
cout << "int foo" << endl;
97
//
}
98
//
99
Foo
<
int
>
::Handle Foo
<
int
>
::foo(Node a)
100
{
101
cout
<<
"
int foo
"
<<
endl;
102
}
103
104
//
Hand<int> Foo<int>::foo(Node a)
105
//
{
106
//
cout << "int foo" << endl;
107
//
}
108
//
109
template
<
typename T
>
110
void
print(T x);
111
112
template
<
typename T
>
113
void
print(T x)
114
{
115
cout
<<
x
<<
endl;
116
}
117
118
template
<
typename T
>
119
template
<
typename U
>
120
void
Foo
<
T
>
::swap(U x)
121
{
122
cout
<<
"
hehe
"
<<
endl;
123
}
124
125
template
<
typename T
>
126
typename Foo
<
T
>
::Handle Foo
<
T
>
::foo(Node a)
127
//
Handle Foo<T>::foo(Node a)
128
{
129
size x
=
23
;
130
cout
<<
x
<<
endl;
131
cout
<<
"
haha
"
<<
endl;
132
}
133
134
template
<
typename T
>
135
typename Foo
<
T
>
::Handle Foo
<
T
>
::foo2(Node a)
136
{
137
cout
<<
"
haha
"
<<
endl;
138
}
139
140
template
<
typename T
>
141
Hand
<
T
>
Foo
<
T
>
::foo3()
142
{
143
cout
<<
"
haha
"
<<
endl;
144
}
145
146
147
int
main(
int
argc,
char
*
argv[])
148
{
149
150
Derive
<>
::print();
151
152
Hand
<
int
>
hand;
153
hand.print();
154
155
Foo
<>
::foo2();
156
Foo
<>
foo;
157
foo.foo(
'
a
'
);
158
159
foo.foo3();
160
161
foo.swap(
3
);
162
163
::print(
10
);
164
165
Foo
<
int
>
fooint;
166
fooint.foo(
4
);
167
168
Foo
<
int
*>
foopint;
169
foopint.foo(
4
);
170
171
return
0
;
172
}
173
//用h2cc.py脚本生成的实现文件框架
1 #include "test.h"
2
3
int
abc(
int
x,
int
y)
4
{
5
6
}
7
8
template
<
9
typename T,
10
template
<
typename
>
class
_Decoder
11
>
12
bool
Hand
<
T, _Decoder
>
::
13
operator
>
(
const
Hand
<
T,_Decoder
>&
other)
14
{
15
16
}
17
18
template
<
19
typename T,
20
template
<
typename
>
class
_Decoder
21
>
22
void
Hand
<
T, _Decoder
>
::print()
23
{
24
25
}
26
27
template
<
typename T
>
28
typename Foo::Handle
29
Foo
<
T
>
::foo(Node a)
30
{
31
32
}
33
34
//
static Handle foo2(Node a = 'a') {
35
//
cout << "haha" << endl;
36
//
}
37
template
<
typename T
>
38
typename Foo::Handle
39
Foo
<
T
>
::foo2(Node a)
40
{
41
42
}
43
44
template
<
typename T
>
45
Hand
<
T
>
Foo
<
T
>
::foo3()
46
{
47
48
}
49
50
template
<
typename T
>
51
template
<
typename U
>
52
void
Foo
<
T
>
::swap(U x)
53
{
54
55
}
56
57
Foo
<
int
>
::Handle
58
Foo
<
int
>
::foo(Node a)
59
{
60
61
}
62
63
template
<
typename T
>
64
Foo
<
T
*>
::Handle
65
Foo
<
T
*>
::foo(Node a)
66
{
67
68
}
69
70
//
Hand<int> Foo<int>::foo(Node a)
71
//
{
72
//
cout << "int foo" << endl;
73
//
}
74
//
75
template
<
typename T
>
76
void
print(T x)
77
{
78
79
}
80
// openmesh 中的一个头文件PolyMeshT.hh生成实现文件框架的示例
//PolyMeshT.hh
1
/*
===========================================================================*\
2
* *
3
* OpenMesh *
4
* Copyright (C) 2001-2009 by Computer Graphics Group, RWTH Aachen *
5
//=============================================================================
6
//
7
// CLASS PolyMeshT
8
//
9
//=============================================================================
10
11
12
#ifndef OPENMESH_POLYMESHT_HH
13
#define OPENMESH_POLYMESHT_HH
14
15
16
//== INCLUDES =================================================================
17
18
19
#include <OpenMesh/Core/System/config.h>
20
#include <OpenMesh/Core/Geometry/MathDefs.hh>
21
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
22
#include <vector>
23
24
25
//== NAMESPACES ===============================================================
26
27
28
namespace OpenMesh {
29
30
31
//== CLASS DEFINITION =========================================================
32
33
34
/** \class PolyMeshT PolyMeshT.hh <OpenMesh/Mesh/PolyMeshT.hh>
35
36
Base type for a polygonal mesh.
37
38
This is the base class for a polygonal mesh. It is parameterized
39
by a mesh kernel that is given as a template argument. This class
40
inherits all methods from its mesh kernel.
41
42
\param Kernel: template argument for the mesh kernel
43
\note You should use the predefined mesh-kernel combinations in
44
\ref mesh_types_group
45
\see \ref mesh_type
46
*/
47
48
template
<
class
Kernel
>
49
class
PolyMeshT :
public
Kernel
50
{
51
public
:
52
53
///
Self type. Used to specify iterators/circulators.
54
typedef PolyMeshT
<
Kernel
>
This;
55
//
--- item types ---
56
57
//
@{
58
///
Determine whether this is a PolyMeshT or TriMeshT ( This function does not check the per face vertex count! It only checks if the datatype is PolyMeshT or TriMeshT )
59
enum
{ IsPolyMesh
=
1
};
60
enum
{ IsTriMesh
=
0
};
61
static
bool
is_polymesh() {
return
true
; }
62
static
bool
is_trimesh() {
return
false
; }
63
//
@}
64
65
///
\name Mesh Items
66
//
@{
67
///
Scalar type
68
typedef typename Kernel::Scalar Scalar;
69
///
Coordinate type
70
typedef typename Kernel::Point Point;
71
///
Normal type
72
typedef typename Kernel::Normal Normal;
73
///
Color type
74
typedef typename Kernel::Color Color;
75
///
TexCoord1D type
76
typedef typename Kernel::TexCoord1D TexCoord1D;
77
///
TexCoord2D type
78
typedef typename Kernel::TexCoord2D TexCoord2D;
79
///
TexCoord3D type
80
typedef typename Kernel::TexCoord3D TexCoord3D;
81
///
Vertex type
82
typedef typename Kernel::Vertex Vertex;
83
///
Halfedge type
84
typedef typename Kernel::Halfedge Halfedge;
85
///
Edge type
86
typedef typename Kernel::Edge Edge;
87
///
Face type
88
typedef typename Kernel::Face Face;
89
//
@}
90
91
//
--- handle types ---
92
93
///
Handle for referencing the corresponding item
94
typedef typename Kernel::VertexHandle VertexHandle;
95
typedef typename Kernel::HalfedgeHandle HalfedgeHandle;
96
typedef typename Kernel::EdgeHandle EdgeHandle;
97
typedef typename Kernel::FaceHandle FaceHandle;
98
99
100
101
typedef typename Kernel::VertexIter VertexIter;
102
typedef typename Kernel::HalfedgeIter HalfedgeIter;
103
typedef typename Kernel::EdgeIter EdgeIter;
104
typedef typename Kernel::FaceIter FaceIter;
105
106
typedef typename Kernel::ConstVertexIter ConstVertexIter;
107
typedef typename Kernel::ConstHalfedgeIter ConstHalfedgeIter;
108
typedef typename Kernel::ConstEdgeIter ConstEdgeIter;
109
typedef typename Kernel::ConstFaceIter ConstFaceIter;
110
//
@}
111
112
//
--- circulators ---
113
114
/*
* \name Mesh Circulators
115
Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators
116
for documentation.
117
*/
118
//
@{
119
///
Circulator
120
typedef typename Kernel::VertexVertexIter VertexVertexIter;
121
typedef typename Kernel::VertexOHalfedgeIter VertexOHalfedgeIter;
122
typedef typename Kernel::VertexIHalfedgeIter VertexIHalfedgeIter;
123
typedef typename Kernel::VertexEdgeIter VertexEdgeIter;
124
typedef typename Kernel::VertexFaceIter VertexFaceIter;
125
typedef typename Kernel::FaceVertexIter FaceVertexIter;
126
typedef typename Kernel::FaceHalfedgeIter FaceHalfedgeIter;
127
typedef typename Kernel::FaceEdgeIter FaceEdgeIter;
128
typedef typename Kernel::FaceFaceIter FaceFaceIter;
129
130
typedef typename Kernel::ConstVertexVertexIter ConstVertexVertexIter;
131
typedef typename Kernel::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter;
132
typedef typename Kernel::ConstVertexIHalfedgeIter ConstVertexIHalfedgeIter;
133
typedef typename Kernel::ConstVertexEdgeIter ConstVertexEdgeIter;
134
typedef typename Kernel::ConstVertexFaceIter ConstVertexFaceIter;
135
typedef typename Kernel::ConstFaceVertexIter ConstFaceVertexIter;
136
typedef typename Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter;
137
typedef typename Kernel::ConstFaceEdgeIter ConstFaceEdgeIter;
138
typedef typename Kernel::ConstFaceFaceIter ConstFaceFaceIter;
139
//
@}
140
141
142
//
--- constructor/destructor
143
PolyMeshT() {}
144
virtual
~
PolyMeshT() {}
145
146
/*
* Uses default copy and assignment operator.
147
Use them to assign two meshes of \b equal type.
148
If the mesh types vary, use PolyMeshT::assign() instead.
*/
149
150
//
--- creation ---
151
inline VertexHandle new_vertex()
152
{
return
Kernel::new_vertex(); }
153
154
inline VertexHandle new_vertex(
const
Point
&
_p)
155
{
156
VertexHandle vh(Kernel::new_vertex());
157
set_point(vh, _p);
158
return
vh;
159
}
160
161
inline VertexHandle add_vertex(
const
Point
&
_p)
162
{
return
new_vertex(_p); }
163
164
//
--- normal vectors ---
165
166
/*
* \name Normal vector computation
167
*/
168
//
@{
169
170
/*
* Calls update_face_normals() and update_vertex_normals() if
171
these normals (i.e. the properties) exist
*/
172
void
update_normals();
173
174
///
Update normal for face _fh
175
void
update_normal(FaceHandle _fh)
176
{ set_normal(_fh, calc_face_normal(_fh)); }
177
178
/*
* Update normal vectors for all faces.
179
\attention Needs the Attributes::Normal attribute for faces.
*/
180
void
update_face_normals();
181
182
/*
* Calculate normal vector for face _fh.
*/
183
Normal calc_face_normal(FaceHandle _fh)
const
;
184
185
/*
* Calculate normal vector for face (_p0, _p1, _p2).
*/
186
Normal calc_face_normal(
const
Point
&
_p0,
const
Point
&
_p1,
187
const
Point
&
_p2)
const
;
188
//
calculates the average of the vertices defining _fh
189
void
calc_face_centroid(FaceHandle _fh, Point
&
_pt)
const
;
190
///
Update normal for vertex _vh
191
void
update_normal(VertexHandle _vh)
192
{ set_normal(_vh, calc_vertex_normal(_vh)); }
193
194
/*
* Update normal vectors for all vertices. \attention Needs the
195
Attributes::Normal attribute for faces and vertices.
*/
196
void
update_vertex_normals();
197
198
/*
* Calculate normal vector for vertex _vh by averaging normals
199
of adjacent faces. Face normals have to be computed first.
200
\attention Needs the Attributes::Normal attribute for faces.
*/
201
Normal calc_vertex_normal(VertexHandle _vh)
const
;
202
203
/*
* Different methods for calculation of the normal at _vh:
204
- -"-_fast - the default one - the same as calc vertex_normal()
205
- needs the Attributes::Normal attribute for faces
206
- -"-_correct - works properly for non-triangular meshes
207
- does not need any attributes
208
- -"-_loop - calculates loop surface normals
209
- does not need any attributes
*/
210
void
calc_vertex_normal_fast(VertexHandle _vh, Normal
&
_n)
const
;
211
void
calc_vertex_normal_correct(VertexHandle _vh, Normal
&
_n)
const
;
212
void
calc_vertex_normal_loop(VertexHandle _vh, Normal
&
_n)
const
;
213
214
215
//
@}
216
217
//
--- Geometry API - still in development ---
218
219
/*
* Calculates the edge vector as the vector defined by
220
the halfedge with id #0 (see below)
*/
221
void
calc_edge_vector(EdgeHandle _eh, Normal
&
_edge_vec)
const
222
{ calc_edge_vector(halfedge_handle(_eh,
0
), _edge_vec); }
223
224
/*
* Calculates the edge vector as the difference of the
225
the points defined by to_vertex_handle() and from_vertex_handle()
*/
226
void
calc_edge_vector(HalfedgeHandle _heh, Normal
&
_edge_vec)
const
227
{
228
_edge_vec
=
point(to_vertex_handle(_heh));
229
_edge_vec
-=
point(from_vertex_handle(_heh));
230
}
231
232
//
Calculates the length of the edge _eh
233
Scalar calc_edge_length(EdgeHandle _eh)
const
234
{
return
calc_edge_length(halfedge_handle(_eh,
0
)); }
235
236
/*
* Calculates the length of the edge _heh
237
*/
238
Scalar calc_edge_length(HalfedgeHandle _heh)
const
239
{
return
(Scalar)sqrt(calc_edge_sqr_length(_heh)); }
240
241
Scalar calc_edge_sqr_length(EdgeHandle _eh)
const
242
{
return
calc_edge_sqr_length(halfedge_handle(_eh,
0
)); }
243
244
Scalar calc_edge_sqr_length(HalfedgeHandle _heh)
const
245
{
246
Normal edge_vec;
247
calc_edge_vector(_heh, edge_vec);
248
return
edge_vec.sqrnorm();
249
}
250
251
/*
* defines a consistent representation of a sector geometry:
252
the halfedge _in_heh defines the sector orientation
253
the vertex pointed by _in_heh defines the sector center
254
_vec0 and _vec1 are resp. the first and the second vectors defining the sector
*/
255
void
calc_sector_vectors(HalfedgeHandle _in_heh, Normal
&
_vec0, Normal
&
_vec1)
const
256
{
257
calc_edge_vector(next_halfedge_handle(_in_heh), _vec0);
//
p2 - p1
258
calc_edge_vector(opposite_halfedge_handle(_in_heh), _vec1);
//
p0 - p1
259
}
260
261
/*
* calculates the sector angle.\n
262
* The vertex pointed by _in_heh defines the sector center
263
* The angle will be calculated between the given halfedge and the next halfedge.\n
264
* Seen from the center vertex this will be the next halfedge in clockwise direction.\n
265
NOTE: only boundary concave sectors are treated correctly
*/
266
Scalar calc_sector_angle(HalfedgeHandle _in_heh)
const
267
{
268
Normal v0, v1;
269
calc_sector_vectors(_in_heh, v0, v1);
270
Scalar denom
=
v0.norm()
*
v1.norm();
271
if
(is_zero(denom))
272
{
273
return
0
;
274
}
275
Scalar cos_a
=
(v0
|
v1)
/
denom;
276
if
(is_boundary(_in_heh))
277
{
//
determine if the boundary sector is concave or convex
278
FaceHandle fh(face_handle(opposite_halfedge_handle(_in_heh)));
279
Normal f_n(calc_face_normal(fh));
//
this normal is (for convex fh) OK
280
Scalar sign_a
=
dot(cross(v0, v1), f_n);
281
return
angle(cos_a, sign_a);
282
}
283
else
284
{
285
return
acos(sane_aarg(cos_a));
286
}
287
}
288
289
//
calculate the cos and the sin of angle <(_in_heh,next_halfedge(_in_heh))
290
/*
291
void calc_sector_angle_cos_sin(HalfedgeHandle _in_heh, Scalar& _cos_a, Scalar& _sin_a) const
292
{
293
Normal in_vec, out_vec;
294
calc_edge_vector(_in_heh, in_vec);
295
calc_edge_vector(next_halfedge_handle(_in_heh), out_vec);
296
Scalar denom = in_vec.norm()*out_vec.norm();
297
if (is_zero(denom))
298
{
299
_cos_a = 1;
300
_sin_a = 0;
301
}
302
else
303
{
304
_cos_a = dot(in_vec, out_vec)/denom;
305
_sin_a = cross(in_vec, out_vec).norm()/denom;
306
}
307
}
308
*/
309
/*
* calculates the normal (non-normalized) of the face sector defined by
310
the angle <(_in_heh,next_halfedge(_in_heh))
*/
311
void
calc_sector_normal(HalfedgeHandle _in_heh, Normal
&
_sector_normal)
const
312
{
313
Normal vec0, vec1;
314
calc_sector_vectors(_in_heh, vec0, vec1);
315
_sector_normal
=
cross(vec0, vec1);
//
(p2-p1)^(p0-p1)
316
}
317
318
/*
* calculates the area of the face sector defined by
319
the angle <(_in_heh,next_halfedge(_in_heh))
320
NOTE: special cases (e.g. concave sectors) are not handled correctly
*/
321
Scalar calc_sector_area(HalfedgeHandle _in_heh)
const
322
{
323
Normal sector_normal;
324
calc_sector_normal(_in_heh, sector_normal);
325
return
sector_normal.norm()
/
2
;
326
}
327
328
/*
* calculates the dihedral angle on the halfedge _heh
329
\attention Needs the Attributes::Normal attribute for faces
*/
330
Scalar calc_dihedral_angle_fast(HalfedgeHandle _heh)
const
331
{
332
CHECK(Kernel::has_face_normals());
333
if
(is_boundary(edge_handle(_heh)))
334
{
//
the dihedral angle at a boundary edge is 0
335
return
0
;
336
}
337
const
Normal
&
n0
=
normal(face_handle(_heh));
338
const
Normal
&
n1
=
normal(face_handle(opposite_halfedge_handle(_heh)));
339
Normal he;
340
calc_edge_vector(_heh, he);
341
Scalar da_cos
=
dot(n0, n1);
342
//
should be normalized, but we need only the sign
343
Scalar da_sin_sign
=
dot(cross(n0, n1), he);
344
return
angle(da_cos, da_sin_sign);
345
}
346
347
/*
* calculates the dihedral angle on the edge _eh
348
\attention Needs the Attributes::Normal attribute for faces
*/
349
Scalar calc_dihedral_angle_fast(EdgeHandle _eh)
const
350
{
return
calc_dihedral_angle_fast(halfedge_handle(_eh,
0
)); }
351
352
//
calculates the dihedral angle on the halfedge _heh
353
Scalar calc_dihedral_angle(HalfedgeHandle _heh)
const
354
{
355
if
(is_boundary(edge_handle(_heh)))
356
{
//
the dihedral angle at a boundary edge is 0
357
return
0
;
358
}
359
Normal n0, n1, he;
360
calc_sector_normal(_heh, n0);
361
calc_sector_normal(opposite_halfedge_handle(_heh), n1);
362
calc_edge_vector(_heh, he);
363
Scalar denom
=
n0.norm()
*
n1.norm();
364
if
(denom
==
Scalar(
0
))
365
{
366
return
0
;
367
}
368
Scalar da_cos
=
dot(n0, n1)
/
denom;
369
//
should be normalized, but we need only the sign
370
Scalar da_sin_sign
=
dot(cross(n0, n1), he);
371
return
angle(da_cos, da_sin_sign);
372
}
373
374
//
calculates the dihedral angle on the edge _eh
375
Scalar calc_dihedral_angle(EdgeHandle _eh)
const
376
{
return
calc_dihedral_angle(halfedge_handle(_eh,
0
)); }
377
378
/*
* tags an edge as a feature if its dihedral angle is larger than _angle_tresh
379
returns the number of the found feature edges, requires edge_status property
*/
380
uint
find_feature_edges(Scalar _angle_tresh
=
OpenMesh::deg_to_rad(
44.0
));
381
//
--- misc ---
382
383
///
Face split (= 1-to-n split)
384
inline
void
split(FaceHandle _fh,
const
Point
&
_p)
385
{ Kernel::split(_fh, add_vertex(_p)); }
386
387
inline
void
split(FaceHandle _fh, VertexHandle _vh)
388
{ Kernel::split(_fh, _vh); }
389
390
inline
void
split(EdgeHandle _eh,
const
Point
&
_p)
391
{ Kernel::split(_eh, add_vertex(_p)); }
392
393
inline
void
split(EdgeHandle _eh, VertexHandle _vh)
394
{ Kernel::split(_eh, _vh); }
395
};
396
397
398
//
=============================================================================
399
}
//
namespace OpenMesh
400
//
=============================================================================
401
#if
defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_POLYMESH_C)
402
# define OPENMESH_POLYMESH_TEMPLATES
403
# include
"
PolyMeshT.cc
"
404
#endif
405
//
=============================================================================
406
#endif
//
OPENMESH_POLYMESHT_HH defined
407
//
=============================================================================
408
//用h2cc.py生成的实现文件框架PolyMeshT.cpp
//PolyMeshT.cpp #h2cc.py自动生成
1 #include "PolyMeshT.hh"
2
3
namespace OpenMesh {
4
5
/**
Calls update_face_normals()
and
update_vertex_normals()
if
6
these normals (i.e. the properties) exist
*/
7
template
<
class
Kernel
>
8
void PolyMeshT
<
Kernel
>
::update_normals()
9
{
10
11
}
12
13
/**
Update normal vectors
for
all faces.
14
\attention Needs the Attributes::Normal attribute
for
faces.
*/
15
template
<
class
Kernel
>
16
void PolyMeshT
<
Kernel
>
::update_face_normals()
17
{
18
19
}
20
21
/**
Calculate normal vector
for
face _fh.
*/
22
template
<
class
Kernel
>
23
typename PolyMeshT::Normal
24
PolyMeshT
<
Kernel
>
::
25
calc_face_normal(FaceHandle _fh) const
26
{
27
28
}
29
30
/**
Calculate normal vector
for
face (_p0, _p1, _p2).
*/
31
template
<
class
Kernel
>
32
typename PolyMeshT::Normal
33
PolyMeshT
<
Kernel
>
::
34
calc_face_normal(const Point
&
_p0, const Point
&
_p1,
35
const Point
&
_p2) const
36
{
37
38
}
39
40
//
calculates the average of the vertices defining _fh
41
template
<
class
Kernel
>
42
void PolyMeshT
<
Kernel
>
::
43
calc_face_centroid(FaceHandle _fh, Point
&
_pt) const
44
{
45
46
}
47
48
/**
Update normal vectors
for
all vertices. \attention Needs the
49
Attributes::Normal attribute
for
faces
and
vertices.
*/
50
template
<
class
Kernel
>
51
void PolyMeshT
<
Kernel
>
::update_vertex_normals()
52
{
53
54
}
55
56
/**
Calculate normal vector
for
vertex _vh by averaging normals
57
of adjacent faces. Face normals have to be computed first.
58
\attention Needs the Attributes::Normal attribute
for
faces.
*/
59
template
<
class
Kernel
>
60
typename PolyMeshT::Normal
61
PolyMeshT
<
Kernel
>
::
62
calc_vertex_normal(VertexHandle _vh) const
63
{
64
65
}
66
67
/**
Different methods
for
calculation of the normal at _vh:
68
-
-
"
-_fast - the default one - the same as calc vertex_normal()
69
-
needs the Attributes::Normal attribute
for
faces
70
-
-
"
-_correct - works properly for non-triangular meshes
71
-
does
not
need any attributes
72
-
-
"
-_loop - calculates loop surface normals
73
-
does
not
need any attributes
*/
74
template
<
class
Kernel
>
75
void PolyMeshT
<
Kernel
>
::
76
calc_vertex_normal_fast(VertexHandle _vh, Normal
&
_n) const
77
{
78
79
}
80
81
template
<
class
Kernel
>
82
void PolyMeshT
<
Kernel
>
::
83
calc_vertex_normal_correct(VertexHandle _vh, Normal
&
_n) const
84
{
85
86
}
87
88
template
<
class
Kernel
>
89
void PolyMeshT
<
Kernel
>
::
90
calc_vertex_normal_loop(VertexHandle _vh, Normal
&
_n) const
91
{
92
93
}
94
95
/**
tags an edge as a feature
if
its dihedral angle
is
larger than _angle_tresh
96
returns the number of the found feature edges, requires edge_status property
*/
97
template
<
class
Kernel
>
98
uint PolyMeshT
<
Kernel
>
::
99
find_feature_edges(Scalar _angle_tresh)
100
{
101
102
}
103
104
}
//
namespace OpenMesh
105
//Openmesh提供的对应PolyMeshT.hh的实现文件PolyMeshT.cc可以和上面自动生成的框架对比一下:)
1 //=============================================================================
2
//
3
//
CLASS PolyMeshT - IMPLEMENTATION
4
//
5
//
=============================================================================
6
7
8
#define
OPENMESH_POLYMESH_C
9
10
11
//
== INCLUDES =================================================================
12
13
#include
<
OpenMesh
/
Core
/
Mesh
/
PolyMeshT.hh
>
14
#include
<
OpenMesh
/
Core
/
Geometry
/
LoopSchemeMaskT.hh
>
15
#include
<
OpenMesh
/
Core
/
Utils
/
vector_cast.hh
>
16
#include
<
OpenMesh
/
Core
/
System
/
omstream.hh
>
17
#include
<
vector
>
18
19
20
//
== NAMESPACES ===============================================================
21
22
23
namespace
OpenMesh {
24
25
//
== IMPLEMENTATION ==========================================================
26
27
template
<
class
Kernel
>
28
uint
PolyMeshT
<
Kernel
>
::find_feature_edges(Scalar _angle_tresh)
29
{
30
assert(Kernel::has_edge_status());
//
this function needs edge status property
31
uint
n_feature_edges
=
0
;
32
for
(EdgeIter e_it
=
Kernel::edges_begin(); e_it
!=
Kernel::edges_end();
++
e_it)
33
{
34
if
(fabs(calc_dihedral_angle(e_it))
>
_angle_tresh)
35
{
//
note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh)
36
status(e_it).set_feature(
true
);
37
n_feature_edges
++
;
38
}
39
else
40
{
41
status(e_it).set_feature(
false
);
42
}
43
}
44
return
n_feature_edges;
45
}
46
47
//
-----------------------------------------------------------------------------
48
49
template
<
class
Kernel
>
50
typename PolyMeshT
<
Kernel
>
::Normal
51
PolyMeshT
<
Kernel
>
::
52
calc_face_normal(FaceHandle _fh)
const
53
{
54
assert(halfedge_handle(_fh).is_valid());
55
ConstFaceVertexIter fv_it(cfv_iter(_fh));
56
57
const
Point
&
p0(point(fv_it));
++
fv_it;
58
const
Point
&
p1(point(fv_it));
++
fv_it;
59
const
Point
&
p2(point(fv_it));
60
61
return
calc_face_normal(p0, p1, p2);
62
}
63
64
65
//
-----------------------------------------------------------------------------
66
67
68
template
<
class
Kernel
>
69
typename PolyMeshT
<
Kernel
>
::Normal
70
PolyMeshT
<
Kernel
>
::
71
calc_face_normal(
const
Point
&
_p0,
72
const
Point
&
_p1,
73
const
Point
&
_p2)
const
74
{
75
#if
1
76
//
The OpenSG <Vector>::operator -= () does not support the type Point
77
//
as rhs. Therefore use vector_cast at this point!!!
78
//
Note! OpenSG distinguishes between Normal and Point!!!
79
Normal p1p0(_p0); p1p0
-=
vector_cast
<
Normal
>
(_p1);
80
Normal p1p2(_p2); p1p2
-=
vector_cast
<
Normal
>
(_p1);
81
82
Normal n
=
cross(p1p2, p1p0);
83
Scalar norm
=
n.length();
84
85
//
The expression ((n *= (1.0/norm)),n) is used because the OpenSG
86
//
vector class does not return self after component-wise
87
//
self-multiplication with a scalar!!!
88
return
(norm
!=
Scalar(
0
))
?
((n
*=
(Scalar(
1
)
/
norm)),n) : Normal(
0
,
0
,
0
);
89
#else
90
Point p1p0
=
_p0; p1p0
-=
_p1;
91
Point p1p2
=
_p2; p1p2
-=
_p1;
92
93
Normal n
=
vector_cast
<
Normal
>
(cross(p1p2, p1p0));
94
Scalar norm
=
n.length();
95
96
return
(norm
!=
0.0
)
?
n
*=
(
1.0
/
norm) : Normal(
0
,
0
,
0
);
97
#endif
98
}
99
100
//
-----------------------------------------------------------------------------
101
102
template
<
class
Kernel
>
103
void
104
PolyMeshT
<
Kernel
>
::
105
calc_face_centroid(FaceHandle _fh, Point
&
_pt)
const
106
{
107
_pt.vectorize(
0
);
108
uint
valence
=
0
;
109
for
(ConstFaceVertexIter cfv_it
=
cfv_iter(_fh); cfv_it;
++
cfv_it,
++
valence)
110
{
111
_pt
+=
point(cfv_it);
112
}
113
_pt
/=
valence;
114
}
115
//
-----------------------------------------------------------------------------
116
117
118
template
<
class
Kernel
>
119
void
120
PolyMeshT
<
Kernel
>
::
121
update_normals()
122
{
123
if
(Kernel::has_face_normals()) update_face_normals();
124
if
(Kernel::has_vertex_normals()) update_vertex_normals();
125
}
126
127
128
//
-----------------------------------------------------------------------------
129
130
131
template
<
class
Kernel
>
132
void
133
PolyMeshT
<
Kernel
>
::
134
update_face_normals()
135
{
136
FaceIter f_it(Kernel::faces_begin()), f_end(Kernel::faces_end());
137
138
for
(; f_it
!=
f_end;
++
f_it)
139
set_normal(f_it.handle(), calc_face_normal(f_it.handle()));
140
}
141
142
143
//
-----------------------------------------------------------------------------
144
145
146
template
<
class
Kernel
>
147
typename PolyMeshT
<
Kernel
>
::Normal
148
PolyMeshT
<
Kernel
>
::
149
calc_vertex_normal(VertexHandle _vh)
const
150
{
151
Normal n;
152
calc_vertex_normal_fast(_vh,n);
153
154
Scalar norm
=
n.length();
155
if
(norm
!=
0.0
) n
*=
(
1.0
/
norm);
156
157
return
n;
158
}
159
160
//
-----------------------------------------------------------------------------
161
template
<
class
Kernel
>
162
void
PolyMeshT
<
Kernel
>
::
163
calc_vertex_normal_fast(VertexHandle _vh, Normal
&
_n)
const
164
{
165
_n.vectorize(
0.0
);
166
for
(ConstVertexFaceIter vf_it
=
cvf_iter(_vh); vf_it;
++
vf_it)
167
_n
+=
normal(vf_it.handle());
168
}
169
170
//
-----------------------------------------------------------------------------
171
template
<
class
Kernel
>
172
void
PolyMeshT
<
Kernel
>
::
173
calc_vertex_normal_correct(VertexHandle _vh, Normal
&
_n)
const
174
{
175
_n.vectorize(
0.0
);
176
ConstVertexIHalfedgeIter cvih_it
=
cvih_iter(_vh);
177
if
(
!
cvih_it)
178
{
//
don't crash on isolated vertices
179
return
;
180
}
181
Normal in_he_vec;
182
calc_edge_vector(cvih_it, in_he_vec);
183
for
( ; cvih_it;
++
cvih_it)
184
{
//
calculates the sector normal defined by cvih_it and adds it to _n
185
if
(is_boundary(cvih_it))
186
{
187
continue
;
188
}
189
HalfedgeHandle out_heh(next_halfedge_handle(cvih_it));
190
Normal out_he_vec;
191
calc_edge_vector(out_heh, out_he_vec);
192
_n
+=
cross(in_he_vec, out_he_vec);
//
sector area is taken into account
193
in_he_vec
=
out_he_vec;
194
in_he_vec
*=
-
1
;
//
change the orientation
195
}
196
}
197
198
//
-----------------------------------------------------------------------------
199
template
<
class
Kernel
>
200
void
PolyMeshT
<
Kernel
>
::
201
calc_vertex_normal_loop(VertexHandle _vh, Normal
&
_n)
const
202
{
203
static
const
LoopSchemeMaskDouble
&
loop_scheme_mask__
=
204
LoopSchemeMaskDoubleSingleton::Instance();
205
206
Normal t_v(
0.0
,
0.0
,
0.0
), t_w(
0.0
,
0.0
,
0.0
);
207
unsigned
int
vh_val
=
valence(_vh);
208
unsigned
int
i
=
0
;
209
for
(ConstVertexOHalfedgeIter cvoh_it
=
cvoh_iter(_vh); cvoh_it;
++
cvoh_it,
++
i)
210
{
211
VertexHandle r1_v(to_vertex_handle(cvoh_it));
212
t_v
+=
(typename Point::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))
*
point(r1_v);
213
t_w
+=
(typename Point::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))
*
point(r1_v);
214
}
215
_n
=
cross(t_w, t_v);
//
hack: should be cross(t_v, t_w), but then the normals are reversed?
216
}
217
218
//
-----------------------------------------------------------------------------
219
220
221
template
<
class
Kernel
>
222
void
223
PolyMeshT
<
Kernel
>
::
224
update_vertex_normals()
225
{
226
VertexIter v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end());
227
228
for
(; v_it
!=
v_end;
++
v_it)
229
set_normal(v_it.handle(), calc_vertex_normal(v_it.handle()));
230
}
231
232
//
=============================================================================
233
}
//
namespace OpenMesh
234
//
=============================================================================
235
//看一个非模版类的示例,google test的一个头文件 gtest-filepath.h
1
2
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
3
#define
GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
4
5
#include
<
gtest
/
internal
/
gtest
-
string
.h
>
6
7
namespace
testing {
8
namespace
internal
{
9
10
//
FilePath - a class for file and directory pathname manipulation which
11
//
handles platform-specific conventions (like the pathname separator).
12
//
Used for helper functions for naming files in a directory for xml output.
13
//
Except for Set methods, all methods are const or static, which provides an
14
//
"immutable value object" -- useful for peace of mind.
15
//
A FilePath with a value ending in a path separator ("like/this/") represents
16
//
a directory, otherwise it is assumed to represent a file. In either case,
17
//
it may or may not represent an actual file or directory in the file system.
18
//
Names are NOT checked for syntax correctness -- no checking for illegal
19
//
characters, malformed paths, etc.
20
21
class
FilePath {
22
public
:
23
FilePath() : pathname_(
""
) { }
24
FilePath(
const
FilePath
&
rhs) : pathname_(rhs.pathname_) { }
25
26
explicit
FilePath(
const
char
*
pathname) : pathname_(pathname) {
27
Normalize();
28
}
29
30
explicit
FilePath(
const
String
&
pathname) : pathname_(pathname) {
31
Normalize();
32
}
33
34
FilePath
&
operator
=
(
const
FilePath
&
rhs) {
35
Set(rhs);
36
return
*
this
;
37
}
38
39
void
Set(
const
FilePath
&
rhs) {
40
pathname_
=
rhs.pathname_;
41
}
42
43
String ToString()
const
{
return
pathname_; }
44
const
char
*
c_str()
const
{
return
pathname_.c_str(); }
45
46
//
Returns the current working directory, or "" if unsuccessful.
47
static
FilePath GetCurrentDir();
48
49
//
Given directory = "dir", base_name = "test", number = 0,
50
//
extension = "xml", returns "dir/test.xml". If number is greater
51
//
than zero (e.g., 12), returns "dir/test_12.xml".
52
//
On Windows platform, uses \ as the separator rather than /.
53
static
FilePath MakeFileName(
const
FilePath
&
directory,
54
const
FilePath
&
base_name,
55
int
number,
56
const
char
*
extension);
57
58
//
Given directory = "dir", relative_path = "test.xml",
59
//
returns "dir/test.xml".
60
//
On Windows, uses \ as the separator rather than /.
61
static
FilePath ConcatPaths(
const
FilePath
&
directory,
62
const
FilePath
&
relative_path);
63
64
//
Returns a pathname for a file that does not currently exist. The pathname
65
//
will be directory/base_name.extension or
66
//
directory/base_name_<number>.extension if directory/base_name.extension
67
//
already exists. The number will be incremented until a pathname is found
68
//
that does not already exist.
69
//
Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
70
//
There could be a race condition if two or more processes are calling this
71
//
function at the same time -- they could both pick the same filename.
72
static
FilePath GenerateUniqueFileName(
const
FilePath
&
directory,
73
const
FilePath
&
base_name,
74
const
char
*
extension);
75
76
//
Returns true iff the path is NULL or "".
77
bool
IsEmpty()
const
{
return
c_str()
==
NULL
||
*
c_str()
==
'
\0
'
; }
78
79
//
If input name has a trailing separator character, removes it and returns
80
//
the name, otherwise return the name string unmodified.
81
//
On Windows platform, uses \ as the separator, other platforms use /.
82
FilePath RemoveTrailingPathSeparator()
const
;
83
84
//
Returns a copy of the FilePath with the directory part removed.
85
//
Example: FilePath("path/to/file").RemoveDirectoryName() returns
86
//
FilePath("file"). If there is no directory part ("just_a_file"), it returns
87
//
the FilePath unmodified. If there is no file part ("just_a_dir/") it
88
//
returns an empty FilePath ("").
89
//
On Windows platform, '\' is the path separator, otherwise it is '/'.
90
FilePath RemoveDirectoryName()
const
;
91
92
//
RemoveFileName returns the directory path with the filename removed.
93
//
Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
94
//
If the FilePath is "a_file" or "/a_file", RemoveFileName returns
95
//
FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
96
//
not have a file, like "just/a/dir/", it returns the FilePath unmodified.
97
//
On Windows platform, '\' is the path separator, otherwise it is '/'.
98
FilePath RemoveFileName()
const
;
99
100
//
Returns a copy of the FilePath with the case-insensitive extension removed.
101
//
Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
102
//
FilePath("dir/file"). If a case-insensitive extension is not
103
//
found, returns a copy of the original FilePath.
104
FilePath RemoveExtension(
const
char
*
extension)
const
;
105
106
//
Creates directories so that path exists. Returns true if successful or if
107
//
the directories already exist; returns false if unable to create
108
//
directories for any reason. Will also return false if the FilePath does
109
//
not represent a directory (that is, it doesn't end with a path separator).
110
bool
CreateDirectoriesRecursively()
const
;
111
112
//
Create the directory so that path exists. Returns true if successful or
113
//
if the directory already exists; returns false if unable to create the
114
//
directory for any reason, including if the parent directory does not
115
//
exist. Not named "CreateDirectory" because that's a macro on Windows.
116
bool
CreateFolder()
const
;
117
118
//
Returns true if FilePath describes something in the file-system,
119
//
either a file, directory, or whatever, and that something exists.
120
bool
FileOrDirectoryExists()
const
;
121
122
//
Returns true if pathname describes a directory in the file-system
123
//
that exists.
124
bool
DirectoryExists()
const
;
125
126
//
Returns true if FilePath ends with a path separator, which indicates that
127
//
it is intended to represent a directory. Returns false otherwise.
128
//
This does NOT check that a directory (or file) actually exists.
129
bool
IsDirectory()
const
;
130
131
//
Returns true if pathname describes a root directory. (Windows has one
132
//
root directory per disk drive.)
133
bool
IsRootDirectory()
const
;
134
135
//
Returns true if pathname describes an absolute path.
136
bool
IsAbsolutePath()
const
;
137
138
private
:
139
//
Replaces multiple consecutive separators with a single separator.
140
//
For example, "bar
//
/foo" becomes "bar/foo". Does not eliminate other
141
//
redundancies that might be in a pathname involving "." or "..".
142
//
143
//
A pathname with multiple consecutive separators may occur either through
144
//
user error or as a result of some scripts or APIs that generate a pathname
145
//
with a trailing separator. On other platforms the same API or script
146
//
may NOT generate a pathname with a trailing "/". Then elsewhere that
147
//
pathname may have another "/" and pathname components added to it,
148
//
without checking for the separator already being there.
149
//
The script language and operating system may allow paths like "foo
//
bar"
150
//
but some of the functions in FilePath will not handle that correctly. In
151
//
particular, RemoveTrailingPathSeparator() only removes one separator, and
152
//
it is called in CreateDirectoriesRecursively() assuming that it will change
153
//
a pathname from directory syntax (trailing separator) to filename syntax.
154
155
void
Normalize();
156
157
String pathname_;
158
};
//
class FilePath
159
160
}
//
namespace internal
161
}
//
namespace testing
162
163
#endif
//
GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
164
//由h2cc.py生成的 gtest-filepath.cc实现框架
1 #include "gtest-filepath.h"
2
3
namespace
testing {
4
5
namespace
internal
{
6
7
//
Returns the current working directory, or "" if unsuccessful.
8
FilePath FilePath::GetCurrentDir()
9
{
10
11
}
12
13
//
Given directory = "dir", base_name = "test", number = 0,
14
//
extension = "xml", returns "dir/test.xml". If number is greater
15
//
than zero (e.g., 12), returns "dir/test_12.xml".
16
//
On Windows platform, uses \ as the separator rather than /.
17
FilePath FilePath::
18
MakeFileName(
const
FilePath
&
directory,
19
const
FilePath
&
base_name,
20
int
number,
21
const
char
*
extension)
22
{
23
24
}
25
26
//
Given directory = "dir", relative_path = "test.xml",
27
//
returns "dir/test.xml".
28
//
On Windows, uses \ as the separator rather than /.
29
FilePath FilePath::
30
ConcatPaths(
const
FilePath
&
directory,
31
const
FilePath
&
relative_path)
32
{
33
34
}
35
36
//
Returns a pathname for a file that does not currently exist. The pathname
37
//
will be directory/base_name.extension or
38
//
directory/base_name_<number>.extension if directory/base_name.extension
39
//
already exists. The number will be incremented until a pathname is found
40
//
that does not already exist.
41
//
Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
42
//
There could be a race condition if two or more processes are calling this
43
//
function at the same time -- they could both pick the same filename.
44
FilePath FilePath::
45
GenerateUniqueFileName(
const
FilePath
&
directory,
46
const
FilePath
&
base_name,
47
const
char
*
extension)
48
{
49
50
}
51
52
//
If input name has a trailing separator character, removes it and returns
53
//
the name, otherwise return the name string unmodified.
54
//
On Windows platform, uses \ as the separator, other platforms use /.
55
FilePath FilePath::
56
RemoveTrailingPathSeparator()
const
57
{
58
59
}
60
61
//
Returns a copy of the FilePath with the directory part removed.
62
//
Example: FilePath("path/to/file").RemoveDirectoryName() returns
63
//
FilePath("file"). If there is no directory part ("just_a_file"), it returns
64
//
the FilePath unmodified. If there is no file part ("just_a_dir/") it
65
//
returns an empty FilePath ("").
66
//
On Windows platform, '\' is the path separator, otherwise it is '/'.
67
FilePath FilePath::RemoveDirectoryName()
const
68
{
69
70
}
71
72
//
RemoveFileName returns the directory path with the filename removed.
73
//
Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
74
//
If the FilePath is "a_file" or "/a_file", RemoveFileName returns
75
//
FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
76
//
not have a file, like "just/a/dir/", it returns the FilePath unmodified.
77
//
On Windows platform, '\' is the path separator, otherwise it is '/'.
78
FilePath FilePath::RemoveFileName()
const
79
{
80
81
}
82
83
//
Returns a copy of the FilePath with the case-insensitive extension removed.
84
//
Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
85
//
FilePath("dir/file"). If a case-insensitive extension is not
86
//
found, returns a copy of the original FilePath.
87
FilePath FilePath::
88
RemoveExtension(
const
char
*
extension)
const
89
{
90
91
}
92
93
//
Creates directories so that path exists. Returns true if successful or if
94
//
the directories already exist; returns false if unable to create
95
//
directories for any reason. Will also return false if the FilePath does
96
//
not represent a directory (that is, it doesn't end with a path separator).
97
bool
FilePath::CreateDirectoriesRecursively()
const
98
{
99
100
}
101
102
//
Create the directory so that path exists. Returns true if successful or
103
//
if the directory already exists; returns false if unable to create the
104
//
directory for any reason, including if the parent directory does not
105
//
exist. Not named "CreateDirectory" because that's a macro on Windows.
106
bool
FilePath::CreateFolder()
const
107
{
108
109
}
110
111
//
Returns true if FilePath describes something in the file-system,
112
//
either a file, directory, or whatever, and that something exists.
113
bool
FilePath::FileOrDirectoryExists()
const
114
{
115
116
}
117
118
//
Returns true if pathname describes a directory in the file-system
119
//
that exists.
120
bool
FilePath::DirectoryExists()
const
121
{
122
123
}
124
125
//
Returns true if FilePath ends with a path separator, which indicates that
126
//
it is intended to represent a directory. Returns false otherwise.
127
//
This does NOT check that a directory (or file) actually exists.
128
bool
FilePath::IsDirectory()
const
129
{
130
131
}
132
133
//
Returns true if pathname describes a root directory. (Windows has one
134
//
root directory per disk drive.)
135
bool
FilePath::IsRootDirectory()
const
136
{
137
138
}
139
140
//
Returns true if pathname describes an absolute path.
141
bool
FilePath::IsAbsolutePath()
const
142
{
143
144
}
145
146
void
FilePath::Normalize()
147
{
148
149
}
150
151
}
//
namespace internal
152
153
}
//
namespace testing
154