嗯,现在基本没问题了,个人觉得类似python,java那样把类的实现完全写到类里面写起来更方便更快,(当然VC有写类函数的时候利用对话框自动生成实现函数的框架),我把程序放到了google code上:
http://code.google.com/p/h2cc/
利用Python脚本可以自动生成相应实现文件。
使用方法如下: h2cc.py -a a.h
//a.h
int abc(); //函数声明会转换到实现文件中
int nba() { //这种函数实现写法默认为在头文件中不变化
int x = 3;
}
int def() //这种函数实现写法{在单独一行,会自动转化到实现文件中
{
int x = 3;
}
转换之后
//a.h
int abc();
int nba() {
int x = 3;
}
int def() ;
//a.cc
#include "a.h"
int abc()
{
}
int def()
{
int x = 3;
}
上面是最简单的示例,对于类和模版类也适用。
-a 表示会自动将上面的def这样的函数转换,而python3.1 a.h 没有-a选项的话,需要用户标明哪些函数要转到实现文件中,方法是如下的写法加一个多余的;在()后面
int def() ;
{
int x = 3;
}
因为.h文件会变化,所以会备份执行操作前的a.h到a.h.bak.
另外有一个-t选项,开启-t的话表示处理模版类的情况即如下会加入些别的信息
在a.h 的namesapce 结束后
#ifndef A_CC_
#include "a.cc"
#endif
在a.cc文件的开头
#define A_CC_
#include "a.h"
这么做是为了避免循环引用是借鉴Openmesh的做法,对于模版函数的实现用户可以直接实现在.h文件中,现在我只支持分离的写法,这样更清晰些。
嗯看下实例,我原来将所有的模版类的函数都实现在.h类的定义内部,这样写起来很方便,但是看起来不舒服,希望把实现的部分,分离到.cc中。
于是调用python3.1 h2cc.py -a -t huff_tree.h 生成合适的huff_tree.cc并适当修改huff_tree.h,所以工作都由h2cc.py自动完成。已验证转换后通过编译链接。
当然目前不保证有些情况可能会出现未知的bug,那样用户可以参考头文件的拷贝文件.h.bak修正。
//原来写好的头文件
1 /*
3 * This is easier to implement but will cost more space.
4 *
5 * For the implementation of differnting internal and leaf
6 * refering to "A practical introduction to data structure
7 * and algorithm analisis p 115"
8 * */
9 #ifndef _HUFF_TREE_H_
10 #define _HUFF_TREE_H_ //TODO automate this for .h file
11
12 #include "type_traits.h"
13 #include "buffer.h"
14 #include "assert.h"
15 #include <queue>
16 #include <deque>
17 #include <vector>
18 #include <functional>
19 #include <iostream>
20 namespace glzip{
21 //----------------------------------------------------------------------------HuffNode------
22 template <typename _KeyType>
23 struct HuffNode {
24 typedef HuffNode<_KeyType> Node;
25 ///allow default construct
26 HuffNode() {}
27 ///construct a new leaf for character key or string key
28 HuffNode(_KeyType key, size_t weight = 0)
29 : key_(key), weight_(weight),
30 left_(NULL), right_(NULL){}
31
32 ///construct a internal leaf from two child
33 //TODO from const to non const fail
34 HuffNode(HuffNode* lchild, HuffNode* rchild)
35 : left_(lchild), right_(rchild) {
36 weight_ = lchild->weight() + rchild->weight();
37 }
38
39 _KeyType key() const{
40 return key_;
41 }
42
43 size_t weight() const {
44 return weight_;
45 }
46
47 Node* left() const {
48 return left_;
49 }
50
51 Node* right() const {
52 return right_;
53 }
54
55 bool is_leaf() {
56 return !left_; //left_ is NULL means right_ is also,for huf tree it is a full binary tree,every internal node is of degree 2
57 }
58
59 /////The comparison operator used to order the priority queue.
60 ////-----But I choose to use the func object for storing pointer in the queuq
61 ////-----not the Node it's self, TODO see the performance differnce
62 //bool operator > (const HuffNode& other) const {
63 // return weight > other.weight;
64 //}
65
66 //-------------------------------------------------------------------
67 _KeyType key_;
68 size_t weight_; //here weight is frequency of char or string
69 Node* left_;
70 Node* right_;
71 };
72
73 //-----------------------------------------------HuffTree-------------------HuffTreeBase----
74 /**
75 * For HuffTree
76 * It take the frequency_map_ and encode_map_ as input.
77 * Those two are not owned by HuffTree but HuffEncoder.
78 * HuffTree will use frequence_map_ info to make encode_map_ ok.
79 * 1. Wait until frequency_map_ is ready (which is handled by HuffEncoder)
80 * 2. build_tree()
81 * 3. gen_encode()
82 * 4. serialize_tree()
83 * The sequence is important can not break!
84 *
85 * TODO(Array based HuffTree) actually the hufftree can be implemented using simple array do
86 * not need building the tree.
87 *
88 * TODO For string type the tree might be so big, the rec is OK?
89 * */
90 template <typename _KeyType>
91 class HuffTreeBase {
92 public:
93 typedef HuffNode<_KeyType> Node;
94 public:
95 void set_root(Node* other) {
96 root_ = other;
97 }
98
99 void delete_tree(Node* root) { //TODO rec what if the tree is so big?
100 if (root) {
101 delete_tree(root->left());
102 delete_tree(root->right());
103 delete root;
104 }
105 }
106
107 //for test
108 void travel(Node* root) {
109 if (root) {
110 travel(root->left());
111 travel(root->right());
112 }
113 }
114
115 Node* root() const {
116 return root_;
117 }
118 protected:
119 Node* root_;
120 };
121
122 //---------------------------------------------------------------------------HuffTree for encode---
123 template <typename _KeyType, typename _TreeType = encode_hufftree>
124 class HuffTree: public HuffTreeBase<_KeyType> {
125 public:
126 using HuffTreeBase<_KeyType>::root;
127 using HuffTreeBase<_KeyType>::set_root;
128 using HuffTreeBase<_KeyType>::delete_tree;
129
130 typedef typename TypeTraits<_KeyType>::type_catergory type_catergory;
131 typedef typename TypeTraits<_KeyType>::FrequencyHashMap FrequencyHashMap;
132 typedef typename TypeTraits<_KeyType>::EncodeHashMap EncodeHashMap;
133 typedef HuffNode<_KeyType> Node;
134
135 struct HuffNodePtrGreater:
136 public std::binary_function<const Node *, const Node *, bool> {
137
138 bool operator() (const Node *p1, const Node *p2) {
139 return p1->weight() > p2->weight();
140 }
141 };
142 //typedef std::deque<Node> HuffDQU; //TODO use vector to see which is better and why
143 //typedef std::priority_queue<Node,HuffDQU, greater<Node> > HuffPRQUE; //desending order use less<HuffNode> if asending
144 typedef std::deque<Node*> HuffDQU; //TODO use vector to see which is better and why
145 typedef std::priority_queue<Node*, HuffDQU, HuffNodePtrGreater> HuffPRQUE; //desending order use less<HuffNode> if asending
146
147 public:
148 HuffTree(EncodeHashMap& encode_map, FrequencyHashMap& frequency_map) //long long int (&)[256] can not be inited by const long
149 : encode_map_(encode_map), frequency_map_(frequency_map)
150 {
151 build_tree(); //assmue frequency_map is ready when creating the tree
152 }
153 ~HuffTree() {
154 //std::cout << "dstruct hufftree\n";
155 delete_tree(root());
156 }
157 void gen_encode() {
158 std::string encode;
159 do_gen_encode(root(), encode);
160 //std::cout << "Finished encoding\n";
161 }
162 void build_tree()
163 {
164 init_queue(type_catergory());
165 int times = pqueue_.size() - 1;
166 for (int i = 0; i < times; i++) {
167 Node* lchild = pqueue_.top();
168 pqueue_.pop();
169 Node* rchild = pqueue_.top();
170 pqueue_.pop();
171 Node* p_internal = new Node(lchild, rchild);
172 pqueue_.push(p_internal);
173 }
174 set_root(pqueue_.top());
175 //std::cout << "Finished building tree\n";
176 }
177
178 ///write the header info to the outfile, for decompressor to rebuild the tree
179 //----write in pre order travelling
180 void serialize_tree(FILE* outfile) {
181 Buffer writer(outfile); //the input outfile cur should be at 0
182 do_serialize_tree(root(), writer);
183 writer.flush_buf(); //make sure writting to the file
184 }
185 private:
186 void init_queue(char_tag) {
187 for(int i = 0; i < 256; i++) {
188 if (frequency_map_[i]) {
189 Node* p_leaf = new Node(i, frequency_map_[i]); //key is i and weight is frequency_map_[i]
190 pqueue_.push(p_leaf); //push leaf
191 }
192 }
193 }
194
195 //TODO try to use char[256] to speed up!
196 void do_gen_encode(Node* root, std::string& encode)
197 {
198 if (root->is_leaf()) {
199 encode_map_[root->key()] = encode;
200 return;
201 }
202 encode.append("0"); //TODO how string operation is implemented what is the effecience??
203 do_gen_encode(root->left(), encode);
204 encode[encode.size() - 1] = '1';
205 do_gen_encode(root->right(), encode);
206 encode.erase(encode.size() - 1, 1);
207 }
208
209 //void do_gen_encode(Node* root, std::string encode) {
210 // //if (root->is_leaf()) {
211 // //if (root->left() == NULL || root->right() == NULL) {
212 // // //encode_map_[root->key()] = encode;
213 // // return;
214 // //}
215 // if (!root->right() && !root->left())
216 // return;
217 // do_gen_encode(root->left(), encode + "0");
218 // do_gen_encode(root->right(), encode + "1");
219 //}
220
221
222 //serialize like (1, 1), (1, 1), (0, 'a').
223 void do_serialize_tree(Node* root, Buffer& writer)
224 {
225 if (root->is_leaf()) {
226 writer.write_byte(0); //0 means the leaf
227 writer.write_byte(root->key()); //write the key
228 return;
229 }
230 writer.write_byte(255); //255 means the internal node
231 writer.write_byte(255); //any num is ok
232 do_serialize_tree(root->left(), writer);
233 do_serialize_tree(root->right(), writer);
234 }
235
236 //----------------------------------------------------for string_tag--------
237 void init_queue(string_tag) {
238
239 }
240 private:
241 HuffPRQUE pqueue_;
242 EncodeHashMap& encode_map_;
243 FrequencyHashMap& frequency_map_;
244 };
245
246 //---------------------------------------------------------------------------HuffTree for decode---
247 /** Specitialized HuffTree for decoding*/
248 template <typename _KeyType>
249 class HuffTree<_KeyType, decode_hufftree>
250 : public HuffTreeBase<_KeyType>{
251 public:
252 using HuffTreeBase<_KeyType>::root;
253 using HuffTreeBase<_KeyType>::root_;
254 using HuffTreeBase<_KeyType>::set_root;
255 using HuffTreeBase<_KeyType>::delete_tree;
256 typedef HuffNode<_KeyType> Node;
257
258 public:
259 HuffTree(FILE* infile, FILE* outfile)
260 :infile_(infile), outfile_(outfile),
261 reader_(infile) {}
262
263 ~HuffTree() {
264 delete_tree(root());
265 }
266
267 ///build_tree() is actually get_encode_info()
268 void build_tree() { //From the infile header info we can build the tree
269 do_build_tree(root_);
270 }
271
272 //help debug to see if the tree rebuild from file is the same as the intial one
273 void do_gen_encode(Node* root, std::string& encode)
274 {
275 if (root->is_leaf()) {
276 std::cout << root->key() << " " << encode << "\n";
277 return;
278 }
279 encode.append("0"); //TODO how string operation is implemented what is the effecience??
280 do_gen_encode(root->left(), encode);
281 encode[encode.size() - 1] = '1';
282 do_gen_encode(root->right(), encode);
283 encode.erase(encode.size() - 1, 1);
284 }
285
286 void decode_file();
287 private:
288 void do_build_tree(Node*& root)
289 {
290 unsigned char first, second;
291 reader_.read_byte(first);
292 reader_.read_byte(second);
293 if (first == 0) { //is leaf TODO actually we do not need weight this time so HuffNode can be smaller
294 root = new Node(second);
295 return;
296 }
297 root = new Node();
298 do_build_tree(root