1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 module hunt.collection.Radix;
12 
13 import std.stdio;
14 
15 import core.memory;
16 import core.stdc.string;
17 import core.stdc.stdlib;
18 
19 private:
20 
21 void debug_log(A...)(A args)
22 {
23     return;
24 }
25 
26 alias log_info = debug_log;
27 alias log_error = debug_log;
28 
29 struct RadixNode
30 {
31     size_t args;
32     //	1 	iskey	
33     //	1	isNull	don't store it 
34     //	1	isCompr 
35     //	29	size
36 
37     //void *data;
38 
39     //	node is not compr
40     //  [abc][a-ptr][b-ptr][c-ptr](value-ptr?)
41     //	
42     //  node is compr
43     //	[xyz][z-ptr](value-ptr?)
44 
45 pragma(inline, true):
46 
47     @property char* str()
48     {
49         return cast(char*)(&this + 1);
50     }
51 
52     @property bool iskey()
53     {
54         return cast(bool)(args & 0x8000_0000UL);
55     }
56 
57     @property bool iskey(bool value)
58     {
59         if (value)
60             args = args | 0x8000_0000UL;
61         else
62             args = args & (~0x8000_0000UL);
63 
64         return value;
65     }
66 
67     @property bool isNull()
68     {
69         return cast(bool)(args & 0x4000_0000UL);
70     }
71 
72     @property bool isNull(bool value)
73     {
74         if (value)
75             args = args | 0x4000_0000UL;
76         else
77             args = args & (~0x4000_0000UL);
78 
79         return value;
80     }
81 
82     @property bool isCompr()
83     {
84         return cast(bool)(args & 0x2000_0000UL);
85     }
86 
87     @property bool isCompr(bool value)
88     {
89         if (value)
90             args = args | 0x2000_0000UL;
91         else
92             args = args & (~0x2000_0000UL);
93 
94         return value;
95     }
96 
97     @property size_t size()
98     {
99         return args & 0x1FFF_FFFFUL;
100     }
101 
102     @property size_t size(size_t value)
103     {
104         size_t v = args & (~0x1FFF_FFFFUL);
105         v += value;
106         args = v;
107 
108         return value;
109     }
110 
111     @property RadixNode** orgin()
112     {
113         return cast(RadixNode**)(str + size);
114     }
115 
116     @property RadixNode* next()
117     {
118         return *orgin;
119     }
120 
121     @property RadixNode* next(RadixNode* n)
122     {
123         *orgin = n;
124         return n;
125     }
126 
127     @property RadixNode* nextChild(size_t index)
128     {
129         assert(index < size);
130         return orgin[index];
131     }
132 
133     @property RadixNode* nextChild(size_t index, RadixNode* n)
134     {
135         orgin[index] = n;
136         return n;
137     }
138 
139     @property void* value()
140     {
141         if (isCompr)
142             return orgin[1];
143         else
144             return orgin[size];
145     }
146 
147     @property void* value(void* v)
148     {
149         if (isCompr)
150             orgin[1] = cast(RadixNode*) v;
151         else
152             orgin[size] = cast(RadixNode*) v;
153         return v;
154     }
155 
156 pragma(inline, false):
157 
158     //alloc non-compr node
159     static RadixNode* create(size_t children, bool hasdata)
160     {
161         size_t nodesize = RadixNode.sizeof + children + (RadixNode*).sizeof * children;
162         if (hasdata)
163             nodesize += (void*).sizeof;
164 
165         RadixNode* n = cast(RadixNode*) malloc(nodesize);
166         if (n is null)
167             return null;
168         memset(n, 0, nodesize);
169 
170         n.iskey = false;
171         n.isNull = false;
172         n.isCompr = false;
173         n.size = children;
174 
175         return n;
176     }
177 
178     static RadixNode* createComp(size_t length, bool hasdata)
179     {
180         size_t nodesize = RadixNode.sizeof + length + (RadixNode*).sizeof;
181         if (hasdata)
182             nodesize += (void*).sizeof;
183 
184         RadixNode* n = cast(RadixNode*) malloc(nodesize);
185         if (n is null)
186             return null;
187         memset(n, 0, nodesize);
188 
189         n.iskey = false;
190         n.isNull = false;
191         n.isCompr = true;
192         n.size = length;
193 
194         return n;
195     }
196 
197     static RadixNode* recreate(RadixNode* n, size_t children, bool hasdata)
198     {
199         size_t nodesize = RadixNode.sizeof + children + (RadixNode*).sizeof * children;
200         if (hasdata)
201             nodesize += (void*).sizeof;
202 
203         auto node = cast(RadixNode*) realloc(n, nodesize);
204         if (node is null)
205             return null;
206         memset(node, 0, nodesize);
207 
208         node.isCompr = false;
209         return node;
210     }
211 
212     static RadixNode* recreateComp(RadixNode* n, size_t length, bool hasdata)
213     {
214         size_t nodesize = RadixNode.sizeof + length + (RadixNode*).sizeof * length;
215         if (hasdata)
216             nodesize += (void*).sizeof;
217 
218         auto node = cast(RadixNode*) realloc(n, nodesize);
219         if (node is null)
220             return null;
221         memset(node, 0, nodesize);
222 
223         node.isCompr = true;
224         return node;
225     }
226 
227     static void free(RadixNode* n)
228     {
229         .free(n);
230     }
231 }
232 
233 struct RadixItem
234 {
235     RadixNode* n;
236     size_t index;
237 }
238 
239 public:
240 
241 struct Radix
242 {
243     protected RadixNode* head;
244     protected size_t numnodes;
245     size_t numele;
246 
247     //
248     //	api create
249     //
250     static Radix* create()
251     {
252         Radix* r = cast(Radix*) malloc(Radix.sizeof);
253         if (r is null)
254             return null;
255         memset(r, 0, Radix.sizeof);
256 
257         r.numele = 0;
258         r.numnodes = 1;
259         r.head = RadixNode.createComp(0, false);
260 
261         if (r.head is null)
262         {
263             free(r);
264             return null;
265         }
266         else
267         {
268             r.head.args = 0;
269             return r;
270         }
271     }
272 
273     //
274     //	api Free
275     //
276     static void free(Radix* r)
277     {
278         r.recursiveFree(r.head);
279         .free(r);
280     }
281 
282     //
283     //	api clear
284     //
285     void clear()
286     {
287         recursiveFree(head);
288 
289         numele = 0;
290         numnodes = 1;
291         head = RadixNode.createComp(0, false);
292     }
293 
294     //
295     //	api remove
296     //
297     bool remove(const ubyte[] s)
298     {
299         RadixNode* h = head;
300         RadixNode* p = head;
301         RadixItem[] ts;
302         size_t index = 0;
303         size_t splitpos = 0;
304         size_t last = find(s, h, p, index, splitpos, ts);
305 
306         if (last > 0)
307         {
308             log_error("remove ", cast(string) s, " ", last);
309             return false;
310         }
311         else
312         {
313             if (h.iskey)
314             {
315                 numele--;
316                 h.iskey = false;
317                 if (h.size == 0)
318                 {
319                     if (p.isCompr)
320                     {
321                         //#1	最后一个节点为空	父节点压缩节点 且是key 则去除父节点			
322                         //		   (x)
323                         //			|			- 'test'       (x)
324                         //		('test')	------------->		|
325                         //			|							()
326                         //			()
327                         //
328                         if (p.iskey)
329                         {
330                             h.iskey = true;
331                             h.value = p.value;
332                             if (p == head)
333                             {
334                                 head = h;
335                             }
336                             else
337                             {
338                                 RadixItem item = ts[$ - 2];
339                                 item.n.nextChild(item.index, h);
340                             }
341                             numnodes -= 1;
342                             RadixNode.free(p);
343                             log_info("#####r1");
344                         }
345                         //#2	最后一个节点为空	父节点是压缩节点 不是key 父父节点必须是非压缩节点  
346                         //		   (t)
347                         //			|
348                         //		   (A)
349                         //			|
350                         //		  ['xyz']
351                         //		   /  \				- 'test'
352                         //		 (B)	('test')  ---------------->	
353                         //    	  |		|			
354                         //		 (C)   ()
355                         //
356                         //
357                         //		#1  当['xy']	 size == 2
358                         //				#1 当['xy']不是key,A为压缩节点 && 当B为压缩节点 且不是key,合并三项
359                         //		   (t)
360                         //			|
361                         //		   (A)
362                         //			|
363                         //		  ['xy']
364                         //		   /  \				- 'test'				(t)
365                         //		 (B)	('test')  ---------------->			|
366                         //    	  |		|								(A + 'x' + B)
367                         //		 (C)   ()									|
368                         //													(C)
369                         //
370                         //				#2 当['xy']不是key,A为压缩节点 , 合并两项
371                         //		   (t)
372                         //			|
373                         //		   (A)
374                         //			|										
375                         //		  ['xy']									
376                         //		   /  \				- 'test'				(t)
377                         //		 (B)	('test')  ---------------->			|
378                         //    	  |		|								( A  + 'x')
379                         //		 (C)   ()									|
380                         //													(B)
381                         //													|
382                         //													(C)
383                         //
384                         //				#3 当B为压缩节点 且不是key , 合并两项
385                         //		   (t)
386                         //			|
387                         //		   (A)
388                         //			|										(t)
389                         //		  ['xy']									|
390                         //		   /  \				- 'test'				(A)
391                         //		 (B)	('test')  ---------------->			|
392                         //    	  |		|								( 'x' + B)
393                         //		 (C)   ()									|
394                         //													(C)
395                         //
396                         //				#4 当都不能合并时
397                         //		   (t)
398                         //			|
399                         //		   (A)
400                         //			|										(t)
401                         //		  ['xy']									|
402                         //		   /  \				- 'test'				(A)
403                         //		 (B)	('test')  ---------------->			|
404                         //    	  |		|								  ( 'x')
405                         //		 (C)   ()									|
406                         //													(B)
407                         //													|
408                         //													(C)
409                         else // pp exist. & pp is non compr
410                         {
411                             //pp
412                             if (p == head)
413                             {
414                                 head = h;
415                                 numnodes -= 1;
416                                 log_info("#####r2");
417                             }
418                             else
419                             {
420                                 RadixItem t1 = ts[$ - 2];
421                                 RadixNode* r1 = ts[$ - 2].n;
422                                 if (r1.size == 2)
423                                 {
424                                     RadixNode* pp = null;
425                                     if (ts.length >= 3)
426                                         pp = ts[$ - 3].n;
427 
428                                     bool ppCombine = pp && pp.isCompr && !r1.iskey;
429                                     RadixNode* nh = r1.nextChild(r1.size - 1 - t1.index);
430                                     bool nhCombie = nh.isCompr && !nh.iskey;
431 
432                                     if (ppCombine && nhCombie)
433                                     {
434                                         bool hasdata = pp.iskey && !pp.isNull;
435                                         RadixNode* u = RadixNode.createComp(pp.size + nh.size + 1, hasdata);
436                                         memcpy(u.str, pp.str, pp.size);
437                                         memcpy(u.str + pp.size, r1.str + r1.size - 1 - t1.index, 1);
438                                         memcpy(u.str + pp.size + 1, nh.str, nh.size);
439 
440                                         u.iskey = pp.iskey;
441                                         if (hasdata)
442                                         {
443                                             u.value = pp.value;
444                                         }
445                                         u.next(nh.next);
446                                         if (pp == head)
447                                         {
448                                             head = u;
449                                         }
450                                         else
451                                         {
452                                             RadixItem item = ts[$ - 4];
453                                             item.n.nextChild(item.index, u);
454                                         }
455                                         RadixNode.free(nh);
456                                         RadixNode.free(pp);
457                                         RadixNode.free(p);
458                                         RadixNode.free(h);
459                                         RadixNode.free(r1);
460                                         numnodes -= 4;
461                                         log_info("#####r211");
462                                     }
463                                     else if (ppCombine)
464                                     {
465                                         bool hasdata = pp.iskey && !pp.isNull;
466                                         RadixNode* u = RadixNode.createComp(pp.size + 1, hasdata);
467                                         memcpy(u.str, pp.str, pp.size);
468                                         memcpy(u.str + pp.size, r1.str + r1.size - 1 - t1.index, 1);
469                                         u.next(nh);
470                                         u.iskey = pp.iskey;
471                                         if (hasdata)
472                                         {
473                                             u.value = pp.value;
474                                         }
475 
476                                         if (pp == head)
477                                         {
478                                             head = u;
479                                         }
480                                         else
481                                         {
482                                             RadixItem item = ts[$ - 4];
483                                             item.n.nextChild(item.index, u);
484                                         }
485                                         RadixNode.free(pp);
486                                         RadixNode.free(p);
487                                         RadixNode.free(h);
488                                         RadixNode.free(r1);
489                                         numnodes -= 3;
490 
491                                         log_info("#####r212");
492                                     }
493                                     else if (nhCombie)
494                                     {
495                                         bool hasdata = r1.iskey && !r1.isNull;
496                                         RadixNode* u = RadixNode.createComp(1 + nh.size, hasdata);
497                                         memcpy(u.str, r1.str + r1.size - 1 - t1.index, 1);
498                                         memcpy(u.str + 1, nh.str, nh.size);
499                                         u.iskey = r1.iskey;
500 
501                                         if (hasdata)
502                                         {
503                                             u.value = r1.value;
504                                         }
505 
506                                         u.next(nh.next);
507 
508                                         if (r1 == head)
509                                         {
510                                             head = u;
511                                         }
512                                         else
513                                         {
514                                             RadixItem item = ts[$ - 3];
515                                             log_info(getString(item.n));
516                                             item.n.nextChild(item.index, u);
517                                         }
518                                         RadixNode.free(nh);
519                                         RadixNode.free(p);
520                                         RadixNode.free(h);
521                                         RadixNode.free(r1);
522                                         numnodes -= 3;
523                                         log_info("#####r213");
524                                     }
525                                     else
526                                     {
527                                         bool hasdata = r1.iskey && !r1.isNull;
528                                         RadixNode* n = RadixNode.createComp(1, hasdata);
529                                         n.iskey = r1.iskey;
530                                         if (hasdata)
531                                             n.value = r1.value;
532                                         n.str[0] = r1.str[r1.size - 1 - t1.index];
533                                         n.next(r1.nextChild(r1.size - 1 - t1.index));
534 
535                                         if (r1 == head)
536                                         {
537                                             head = n;
538                                         }
539                                         else
540                                         {
541                                             RadixItem item = ts[$ - 3];
542                                             item.n.nextChild(item.index, n);
543                                         }
544 
545                                         RadixNode.free(h);
546                                         RadixNode.free(p);
547                                         RadixNode.free(r1);
548                                         numnodes -= 2;
549                                         log_info("#####r214");
550                                     }
551                                 }
552                                 //		#1  当['xyz'] 的size > 2
553                                 //				
554                                 //		   (t)										(t)
555                                 //			|										 |
556                                 //		   (A)										(A)
557                                 //			|										 |
558                                 //		  ['xyz']                                   ['xz']
559                                 //		   /  \    \ 				- 'test'	    /   \
560                                 //		 (B)('test') (D)  ---------------->		  ('B')   (D)
561                                 //    	  |		|								
562                                 //		 (C)   ()									
563                                 //													
564                                 else if (r1.size > 2)
565                                 {
566                                     bool hasdata = r1.iskey && !r1.isNull;
567                                     RadixNode* u = RadixNode.create(r1.size - 1, hasdata);
568                                     u.iskey = r1.iskey;
569                                     if (hasdata)
570                                     {
571                                         u.value = r1.value;
572                                     }
573 
574                                     log_info("index ", t1.index, " ", r1.size);
575 
576                                     if (t1.index == 0)
577                                     {
578                                         memcpy(u.str, r1.str + 1, r1.size - 1);
579 
580                                     }
581                                     else if (t1.index == r1.size - 1)
582                                     {
583                                         memcpy(u.str, r1.str, r1.size - 1);
584                                     }
585                                     else
586                                     {
587                                         memcpy(u.str, r1.str, t1.index);
588                                         memcpy(u.str + t1.index, r1.str + t1.index + 1,
589                                                 r1.size - t1.index - 1);
590                                     }
591 
592                                     log_info(getString(u));
593 
594                                     for (size_t i, j = 0; i < r1.size;)
595                                     {
596                                         if (i != t1.index)
597                                             u.orgin[j++] = r1.orgin[i++];
598                                         else
599                                             i++;
600                                     }
601 
602                                     //RadixNode *test = null;
603 
604                                     if (r1 == head)
605                                     {
606                                         head = u;
607                                     }
608                                     else
609                                     {
610                                         RadixItem i = ts[$ - 3];
611 
612                                         i.n.nextChild(i.index, u);
613 
614                                     }
615 
616                                     RadixNode.free(r1);
617                                     RadixNode.free(h);
618                                     RadixNode.free(p);
619 
620                                     numnodes -= 2;
621                                     log_info("####r22");
622                                 }
623                                 else
624                                 {
625                                     log_error("####r23 none exist");
626                                 }
627                             }
628                         }
629                     }
630                     //	#3  当父节点为非压缩节点
631                     //
632                     //
633                     //			 (A)
634                     //			  |					A+'y'
635                     //			['xyz']			----------->
636                     //			 / |  \
637                     //			(C) () (D)
638                     //
639                     //
640                     //
641                     //		#1 当['xy'] 的size == 2时
642                     //				
643                     //				当#1 ['xy']非key,且(C)非key , 合并三项
644                     //			 (t)
645                     //			  |
646                     //			 (A)
647                     //			  |					A+'y'			   (t)
648                     //			['xy']			----------->      	 	|
649                     //			 / |								(A + 'x' + C)
650                     //			(C) () 									|
651                     //			 |										(D)
652                     //			(D)		
653                     //
654                     //		
655                     //				
656                     //				当#2 ['xy']非key , 合并两项
657                     //			 (t)
658                     //			  |
659                     //			 (A)
660                     //			  |					A+'y'			   (t)
661                     //			['xy']			----------->      	 	|
662                     //			 / |								(A + 'x' )
663                     //			(C) () 									|
664                     //			 |										(C)
665                     //			(D)										|
666                     //													(D)
667                     //				当#3 (C)非key , 合并两项
668                     //			 (t)
669                     //			  |									   (t)
670                     //			 (A)								    |
671                     //			  |					A+'y'			   (A)
672                     //			['xy']			----------->      	 	|
673                     //			 / |								('x' + C)
674                     //			(C) () 									|
675                     //			 |										(D)
676                     //			(D)	
677                     //
678                     //			   当#4 无合并
679                     //											
680                     //			 (t)
681                     //			  |									   (t)
682                     //			 (A)								    |
683                     //			  |					A+'y'			   (A)
684                     //			['xy']			----------->      	 	|
685                     //			 / |								  ('x')
686                     //			(C) () 									|
687                     //			 |										(C)
688                     //			(D)										|	
689                     //													(D)
690                     else if (!p.isCompr)
691                     {
692                         // noncompr to compr
693                         log_info("p ", getString(p));
694                         if (p.size == 2)
695                         {
696                             RadixNode* pp = null;
697                             if (ts.length >= 2)
698                                 pp = ts[$ - 2].n;
699                             bool ppCombine = pp && pp.isCompr && !p.iskey;
700                             RadixNode* nh = p.nextChild(p.size - 1 - index);
701 
702                             log_info("nh ", getString(nh));
703                             bool nhCombie = nh.isCompr && !nh.iskey;
704 
705                             log_info(ppCombine, " ", nhCombie);
706 
707                             // #1 合并3个
708                             if (ppCombine && nhCombie)
709                             {
710                                 bool hasdata = pp.iskey && !pp.isNull;
711                                 RadixNode* u = RadixNode.createComp(pp.size + nh.size + 1, hasdata);
712                                 memcpy(u.str, pp.str, pp.size);
713                                 memcpy(u.str + pp.size, p.str + p.size - 1 - index, 1);
714                                 memcpy(u.str + pp.size + 1, nh.str, nh.size);
715 
716                                 u.iskey = pp.iskey;
717                                 if (hasdata)
718                                     u.value = pp.value;
719 
720                                 u.next(nh.next);
721                                 if (pp == head)
722                                 {
723                                     head = u;
724                                 }
725                                 else
726                                 {
727                                     RadixItem item = ts[$ - 3];
728                                     item.n.nextChild(item.index, u);
729                                 }
730                                 RadixNode.free(nh);
731                                 RadixNode.free(pp);
732                                 RadixNode.free(p);
733                                 RadixNode.free(h);
734 
735                                 numnodes -= 3;
736 
737                                 log_info("#####r311");
738                             }
739                             // #2 
740                             else if (ppCombine)
741                             {
742                                 bool hasdata = pp.iskey && !pp.isNull;
743                                 RadixNode* u = RadixNode.createComp(pp.size + 1, hasdata);
744                                 memcpy(u.str, pp.str, pp.size);
745                                 memcpy(u.str + pp.size, p.str + p.size - 1 - index, 1);
746                                 u.next(nh);
747                                 u.iskey = pp.iskey;
748                                 if (hasdata)
749                                     u.value = pp.value;
750 
751                                 if (pp == head)
752                                 {
753                                     head = u;
754                                 }
755                                 else
756                                 {
757                                     RadixItem item = ts[$ - 3];
758                                     item.n.nextChild(item.index, u);
759                                 }
760                                 RadixNode.free(pp);
761                                 RadixNode.free(p);
762                                 RadixNode.free(h);
763                                 numnodes -= 2;
764 
765                                 log_info("#####r312");
766                             }
767                             else if (nhCombie)
768                             {
769                                 bool hasdata = p.iskey && !p.isNull;
770                                 RadixNode* u = RadixNode.createComp(1 + nh.size, hasdata);
771                                 memcpy(u.str, p.str + p.size - 1 - index, 1);
772                                 memcpy(u.str + 1, nh.str, nh.size);
773                                 u.iskey = p.iskey;
774                                 u.next(nh.next);
775                                 if (hasdata)
776                                     u.value = p.value;
777                                 if (p == head)
778                                 {
779                                     head = u;
780                                 }
781                                 else
782                                 {
783                                     RadixItem item = ts[$ - 2];
784                                     item.n.nextChild(item.index, u);
785                                 }
786                                 RadixNode.free(nh);
787                                 RadixNode.free(p);
788                                 RadixNode.free(h);
789                                 numnodes -= 2;
790                                 log_info("#####r313");
791                             }
792                             // p.iskey or no combine.
793                             else
794                             {
795                                 bool hasdata = p.iskey && !p.isNull;
796                                 RadixNode* n = RadixNode.createComp(1, hasdata);
797                                 n.iskey = p.iskey;
798                                 if (hasdata)
799                                     n.value = p.value;
800                                 n.str[0] = p.str[p.size - 1 - index];
801                                 n.next(p.nextChild(p.size - 1 - index));
802 
803                                 if (p == head)
804                                 {
805                                     head = n;
806                                 }
807                                 else
808                                 {
809                                     RadixItem item = ts[$ - 2];
810                                     item.n.nextChild(item.index, n);
811                                 }
812 
813                                 RadixNode.free(h);
814                                 RadixNode.free(p);
815                                 numnodes -= 1;
816                                 log_info("#####r314");
817                             }
818                         }
819                         //		#2 当['xyz'] 的size > 2时
820                         //			 (A)								(A)
821                         //			  |					A+'y'			 |
822                         //			['xyz']			----------->		['xz']
823                         //			 / |  \								/ \
824                         //			(C) () (D)						  (C) (D)
825                         //
826                         //
827                         //
828                         else if (p.size > 2)
829                         {
830                             bool hasdata = p.iskey && !p.isNull;
831                             RadixNode* u = RadixNode.create(p.size - 1, hasdata);
832                             u.iskey = p.iskey;
833                             if (hasdata)
834                             {
835                                 u.value = p.value;
836                             }
837 
838                             log_info("index ", index, " ", p.size);
839 
840                             if (index == 0)
841                             {
842                                 memcpy(u.str, p.str + 1, p.size - 1);
843                             }
844                             else if (index == p.size - 1)
845                             {
846                                 memcpy(u.str, p.str, p.size - 1);
847                             }
848                             else
849                             {
850                                 memcpy(u.str, p.str, index);
851                                 memcpy(u.str + index, p.str + index + 1, p.size - index - 1);
852                             }
853 
854                             for (size_t i, j = 0; i < p.size;)
855                             {
856                                 if (i != index)
857                                     u.orgin[j++] = p.orgin[i++];
858                                 else
859                                     i++;
860                             }
861 
862                             if (p == head)
863                             {
864                                 head = u;
865                             }
866                             else
867                             {
868                                 RadixItem item = ts[$ - 2];
869                                 item.n.nextChild(item.index, u);
870                             }
871 
872                             RadixNode.free(h);
873                             RadixNode.free(p);
874                             numnodes--;
875                             log_info("#####r32");
876                         }
877                     }
878                 }
879                 // h.size > 0
880                 else
881                 {
882                     //	#4 节点是压缩节点 , 则合并
883                     //			  (A)								(A + 'test')
884                     //				|								 	|
885                     //			('test')		- 'test'				(B)
886                     //			   |
887                     //			  (B)		----------->      
888                     //
889                     //
890                     //	#5 只是去掉一个值。
891 
892                     if (h.isCompr && p.isCompr)
893                     {
894                         bool hasdata = p.iskey && !p.isNull;
895                         RadixNode* u = RadixNode.createComp(p.size + h.size, hasdata);
896                         u.iskey = p.iskey;
897                         if (hasdata)
898                         {
899                             u.value = p.value;
900                         }
901 
902                         memcpy(u.str, p.str, p.size);
903                         memcpy(u.str + p.size, h.str, h.size);
904                         u.next(h.next);
905                         if (p == head)
906                         {
907                             head = u;
908                         }
909                         else
910                         {
911                             RadixItem item = ts[$ - 2];
912                             item.n.nextChild(item.index, u);
913                         }
914                         numnodes--;
915                         RadixNode.free(p);
916                         RadixNode.free(h);
917                         log_info("#####r4");
918                     }
919                     else
920                     {
921                         log_info("#####r5");
922                     }
923                 }
924                 return true;
925             }
926             else
927             {
928                 log_error(cast(string) s, " is not key ", getString(h));
929                 return false;
930             }
931         }
932     }
933 
934     //
935     //	api insert
936     //
937     bool insert(const ubyte[] s, void* data)
938     {
939         RadixNode* h = head;
940         RadixNode* p = head;
941         RadixItem[] ts;
942         size_t index = 0;
943         size_t splitpos = 0;
944         numele++;
945 
946         size_t last = find(s, h, p, index, splitpos, ts);
947 
948         log_info("find ", cast(string) s, " last ", last, " split ", splitpos, " index ", index);
949 
950         //没有找到该s.
951         if (last > 0)
952         {
953             // #1 如果该树是空树.
954             //
955             //				'test'
956             //		() ----------->('test')
957             //							 |	
958             //							()
959             //							
960             if (p.size == 0)
961             {
962                 RadixNode* n = RadixNode.createComp(s.length, false);
963                 memcpy(n.str, s.ptr, s.length);
964 
965                 p = RadixNode.recreateComp(p, 0, true);
966                 p.args = 0;
967                 p.iskey = true;
968                 p.value = data;
969 
970                 n.next = p;
971                 head = n;
972 
973                 numnodes++;
974 
975                 log_info("####1");
976                 return true;
977             }
978             else
979             {
980                 // #2 直到匹配到叶子节点,都没有匹配到,必须往该叶子节点后面加剩余的字符。
981                 //				'tester'
982                 //	("test") -------->	("test")
983                 //		|					|
984                 //		()				  ("er")
985                 //							|
986                 //							()
987                 if (h.size == 0)
988                 {
989                     //1 new comp node
990                     RadixNode* n = RadixNode.createComp(last, true);
991                     memcpy(n.str, s[$ - last .. $].ptr, last);
992                     n.iskey = true;
993                     n.value = h.value;
994 
995                     h.value = data;
996 
997                     n.next = h;
998                     p.nextChild(index, n);
999 
1000                     numnodes++;
1001 
1002                     log_info("####2");
1003                     return true;
1004                 }
1005                 //	#3	匹配到压缩节点,1 必须截断前部分。2 取原字符及压缩节点匹配字符构成 两个字符的 非压缩节点。 
1006                 //			3 非压缩节点 两个子节点 分别指向 截断后半部分 及 原字符后半部分
1007                 //
1008                 //				'teacher'
1009                 //	('test')---------------->('te')
1010                 //		|						|
1011                 //		(x)					  ['as']	u2
1012                 //							   / \	
1013                 //					u4 ('cher')  ('t') u3
1014                 //						   /		\
1015                 //					  u5 ()			(x)
1016                 //
1017                 else if (h.isCompr)
1018                 {
1019                     RadixNode* u1;
1020 
1021                     bool hasvalue = h.iskey && !h.isNull;
1022                     auto u2 = RadixNode.create(2, hasvalue && splitpos <= 0);
1023                     u2.str[0] = s[$ - last];
1024                     u2.str[1] = h.str[splitpos];
1025                     numnodes++;
1026 
1027                     if (splitpos > 0)
1028                     {
1029                         u1 = RadixNode.createComp(splitpos, hasvalue);
1030                         memcpy(u1.str, h.str, splitpos);
1031                         u1.iskey = h.iskey;
1032                         if (hasvalue)
1033                             u1.value = h.value;
1034                         numnodes++;
1035                     }
1036                     else
1037                     {
1038                         u1 = u2;
1039                         u1.iskey = h.iskey;
1040                         if (hasvalue)
1041                             u1.value = h.value;
1042                     }
1043 
1044                     size_t u3_len = h.size - splitpos - 1;
1045                     RadixNode* u3;
1046                     bool bcombine = false;
1047                     if (u3_len > 0)
1048                     {
1049                         //combin
1050                         if (h.next.size > 0 && h.next.isCompr && !h.next.iskey)
1051                         {
1052                             u3 = RadixNode.createComp(u3_len + h.next.size, h.next.iskey && !h.next.isNull);
1053                             memcpy(u3.str, h.str + splitpos + 1, h.size - splitpos - 1);
1054                             memcpy(u3.str + h.size - splitpos - 1, h.next.str, h.next.size);
1055                             numnodes++;
1056                             bcombine = true;
1057                         }
1058                         else
1059                         {
1060                             u3 = RadixNode.createComp(h.size - splitpos - 1, false);
1061                             memcpy(u3.str, h.str + splitpos + 1, h.size - splitpos - 1);
1062                             numnodes++;
1063                         }
1064                     }
1065                     else
1066                     {
1067                         u3 = h.next;
1068                     }
1069 
1070                     //4
1071                     size_t u4_len = last - 1;
1072                     RadixNode* u4;
1073 
1074                     //5
1075                     auto u5 = RadixNode.createComp(0, true);
1076                     u5.iskey = true;
1077                     u5.value = data;
1078                     numnodes++;
1079 
1080                     if (u4_len > 0)
1081                     {
1082                         u4 = RadixNode.createComp(last - 1, false);
1083                         memcpy(u4.str, s.ptr + s.length - last + 1, last - 1);
1084                         numnodes++;
1085                     }
1086                     else
1087                     {
1088                         u4 = u5;
1089                     }
1090 
1091                     //relation
1092                     if (u4_len > 0)
1093                         u4.next = u5;
1094 
1095                     if (bcombine)
1096                     {
1097                         u3.next = h.next.next;
1098                         RadixNode.free(h.next);
1099                         numnodes--;
1100                     }
1101                     else if (u3_len > 0)
1102                     {
1103                         u3.next = h.next;
1104                     }
1105 
1106                     u2.nextChild(0, u4);
1107                     u2.nextChild(1, u3);
1108 
1109                     if (splitpos > 0)
1110                         u1.next = u2;
1111 
1112                     p.nextChild(index, u1);
1113 
1114                     if (h == head)
1115                         head = u1;
1116 
1117                     RadixNode.free(h);
1118                     numnodes--;
1119 
1120                     log_info("####3");
1121                     return true;
1122                 }
1123                 // 	#4	都不匹配非压缩节点的任何子节点 1 增加该字符 2 截断原字符
1124                 //	
1125                 //					 'beer'				
1126                 //			["tes"]	--------->	['tesb']
1127                 //			/ / \ 				/ / \  \
1128                 // 		  () () ()             () () () ('eer')
1129                 //											\
1130                 //											()
1131                 else
1132                 {
1133                     bool hasdata = !h.isNull && h.iskey;
1134                     auto i = RadixNode.create(h.size + 1, hasdata);
1135                     i.iskey = h.iskey;
1136                     if (hasdata)
1137                     {
1138                         i.value = h.value; //modify 
1139                     }
1140 
1141                     numnodes++;
1142                     memcpy(i.str, h.str, h.size);
1143                     i.str[h.size] = s[$ - last];
1144                     memcpy(i.str + i.size, h.str + h.size, h.size * (RadixNode*).sizeof);
1145 
1146                     auto u1_len = last - 1;
1147                     RadixNode* u1;
1148 
1149                     auto u2 = RadixNode.createComp(0, true);
1150                     u2.value = data;
1151                     u2.iskey = true;
1152                     numnodes++;
1153                     if (u1_len > 0)
1154                     {
1155                         u1 = RadixNode.createComp(u1_len, false);
1156                         memcpy(u1.str, s.ptr + s.length - last + 1, u1_len);
1157                         numnodes++;
1158                         u1.next = u2;
1159                     }
1160                     else
1161                     {
1162                         u1 = u2;
1163                     }
1164 
1165                     i.nextChild(h.size, u1);
1166                     p.nextChild(index, i);
1167 
1168                     if (h == head)
1169                         head = i;
1170                     RadixNode.free(h);
1171                     numnodes--;
1172                     log_info("####4");
1173                     return true;
1174                 }
1175             }
1176         }
1177         else
1178         {
1179             //	#5	完全匹配,只要改个值 即可。
1180             //							'te'
1181             //				('te')	------------->	 the same
1182             //				  |
1183             //				['as']
1184             //				 /  \
1185             //		  ('cher')  ('t')
1186             //			 |		  |
1187             //			()		 ()
1188             if (splitpos == 0)
1189             {
1190                 bool hasdata = (h.iskey && !h.isNull);
1191                 if (hasdata)
1192                 {
1193                     h.value = data;
1194                     if (h.iskey) //replaced
1195                         numele--;
1196                     else
1197                         assert(0);
1198 
1199                     log_info("####50");
1200                     return false;
1201                 }
1202                 else
1203                 {
1204                     RadixNode* u;
1205                     if (h.isCompr)
1206                     {
1207                         u = RadixNode.recreateComp(h, h.size, true);
1208                         u.args = 0;
1209                     }
1210                     else
1211                     {
1212                         u = RadixNode.recreate(h, h.size, true);
1213                     }
1214 
1215                     u.value = data;
1216                     u.iskey = true;
1217                     p.nextChild(index, u);
1218 
1219                     log_info("####51");
1220                     return true;
1221                 }
1222             }
1223             //	#6	完全匹配压缩节点前半部分。 分割即可。
1224             //					'te'
1225             //	('test')	--------->		('te')
1226             //		|						  |
1227             //	   (x)						('st')
1228             //								  |
1229             //								 (x)
1230             //
1231             else if (h.isCompr)
1232             {
1233                 bool hasdata = (h.iskey && !h.isNull);
1234                 auto u1 = RadixNode.createComp(splitpos, hasdata);
1235                 memcpy(u1.str, h.str, splitpos);
1236                 u1.iskey = h.iskey;
1237                 if (hasdata)
1238                     u1.value = h.value;
1239                 numnodes++;
1240 
1241                 auto u2 = RadixNode.createComp(h.size - splitpos, true);
1242                 memcpy(u2.str, h.str + splitpos, h.size - splitpos);
1243                 u2.iskey = true;
1244                 u2.value = data;
1245                 numnodes++;
1246                 u2.next = h.next;
1247 
1248                 u1.next = u2;
1249 
1250                 RadixNode.free(h);
1251                 numnodes--;
1252                 if (h == head)
1253                 {
1254                     head = u1;
1255                 }
1256                 else
1257                 {
1258                     p.nextChild(index, u1);
1259                 }
1260 
1261                 log_info("####6");
1262                 return true;
1263             }
1264             else
1265             {
1266                 writeln("assert");
1267                 assert(0);
1268             }
1269         }
1270 
1271     }
1272 
1273     //
1274     //	api find
1275     //
1276     bool find(const ubyte[] s, out void* data)
1277     {
1278         RadixNode* h = head;
1279         RadixNode* p = head;
1280         RadixItem[] ts;
1281         size_t index = 0;
1282         size_t splitpos = 0;
1283         size_t last = find(s, h, p, index, splitpos, ts);
1284         if (last == 0 && splitpos == 0 && h.iskey)
1285         {
1286             data = h.value;
1287             return true;
1288         }
1289 
1290         return false;
1291     }
1292 
1293 private:
1294 
1295     void recursiveFree(RadixNode* n)
1296     {
1297         size_t numchildren = 0;
1298         if (n.isCompr)
1299         {
1300             numchildren = n.size > 0 ? 1 : 0;
1301         }
1302         else
1303         {
1304             numchildren = n.size;
1305         }
1306         while (numchildren--)
1307         {
1308             recursiveFree(n.nextChild(numchildren));
1309         }
1310         RadixNode.free(n);
1311         numnodes--;
1312     }
1313 
1314     //find
1315     size_t find(const ubyte[] s, ref RadixNode* r, ref RadixNode* pr, ref size_t index,
1316             ref size_t splitpos, ref RadixItem[] ts)
1317     {
1318         //find it
1319 
1320         if (s.length == 0)
1321         {
1322             return 0;
1323         }
1324 
1325         if (r.size == 0)
1326         {
1327             return s.length;
1328         }
1329 
1330         if (r.isCompr) //is compr
1331         {
1332             char* p = r.str;
1333             size_t i = 0;
1334             for (i = 0; i < r.size && i < s.length; i++)
1335             {
1336                 if (p[i] != s[i])
1337                     break;
1338             }
1339 
1340             if (i == r.size)
1341             {
1342                 pr = r;
1343                 r = r.next;
1344                 index = 0;
1345                 RadixItem item;
1346                 item.n = pr;
1347                 item.index = index;
1348                 ts ~= item;
1349                 return find(s[(*pr).size .. $], r, pr, index, splitpos, ts);
1350             }
1351             else
1352             {
1353                 splitpos = i;
1354                 return s.length - i;
1355             }
1356         }
1357         else
1358         {
1359             char* p = r.str;
1360             char* end = r.str + r.size;
1361             while (p != end)
1362             {
1363                 if (*p == s[0])
1364                     break;
1365                 p++;
1366             }
1367 
1368             size_t i = p - r.str;
1369             if (p == end)
1370             {
1371                 splitpos = i;
1372                 return s.length;
1373             }
1374             else
1375             {
1376                 pr = r;
1377                 index = i;
1378                 r = r.nextChild(index);
1379                 RadixItem item;
1380                 item.n = pr;
1381                 item.index = index;
1382                 ts ~= item;
1383                 return find(s[1 .. $], r, pr, index, splitpos, ts);
1384             }
1385         }
1386     }
1387 
1388     string getString(RadixNode* h)
1389     {
1390         string str;
1391         for (size_t i = 0; i < h.size; i++)
1392             str ~= h.str[i];
1393         return str;
1394     }
1395 
1396     void recursiveShow(RadixNode* n, size_t level)
1397     {
1398         show(n, level);
1399 
1400         if (n.size == 0)
1401             return;
1402 
1403         if (n.isCompr)
1404         {
1405             recursiveShow(n.next, ++level);
1406         }
1407         else
1408         {
1409             ++level;
1410             for (size_t i = 0; i < n.size; i++)
1411             {
1412                 recursiveShow(n.nextChild(i), level);
1413             }
1414         }
1415     }
1416 
1417     void show(RadixNode* n, size_t level)
1418     {
1419         for (size_t i = 0; i < level; i++)
1420             write("\t");
1421         write(" key:", n.iskey, n.isCompr ? " (" : " [");
1422 
1423         for (size_t i = 0; i < n.size; i++)
1424             write(n.str[i]);
1425 
1426         write(n.isCompr ? ") " : "] ", (n.iskey && !n.isNull) ? n.value : null, "\n");
1427     }
1428 
1429     void show()
1430     {
1431         RadixNode* p = head;
1432         writef("numele:%d numnodes:%d\n", numele, numnodes);
1433 
1434         recursiveShow(p, 0);
1435 
1436         writef("\n");
1437     }
1438 };
1439 
1440 unittest
1441 {
1442     void test1()
1443     {
1444         string[] toadd = [
1445             "alligator", "alien", "baloon", "chromodynamic", "romane", "romanus",
1446             "romulus", "rubens", "ruber", "rubicon", "rubicundus", "all", "rub", "ba"
1447         ];
1448         Radix* r = Radix.create();
1449         foreach (i, s; toadd)
1450         {
1451             r.insert(cast(ubyte[]) s, cast(void*) i);
1452         }
1453 
1454         foreach (s; toadd)
1455         {
1456             r.remove(cast(ubyte[]) s);
1457         }
1458         r.show();
1459     }
1460 
1461     void test2()
1462     {
1463         string origin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ~ "abcdefghijklmnopqrstuvwxyz" ~ "0123456789";
1464         import std.random;
1465 
1466         string[] keys;
1467         size_t num = 1000;
1468 
1469         for (size_t j = 0; j < num; j++)
1470         {
1471             size_t len = uniform(1, 16);
1472             string key;
1473             for (size_t i = 0; i < len; i++)
1474             {
1475                 size_t index = uniform(0, origin.length);
1476                 key ~= origin[index];
1477             }
1478             keys ~= key;
1479         }
1480 
1481         Radix* r = Radix.create();
1482         foreach (i, k; keys)
1483         {
1484             r.insert(cast(ubyte[]) k, cast(void*) i);
1485         }
1486 
1487         foreach (k; keys)
1488         {
1489             r.remove(cast(ubyte[]) k);
1490         }
1491 
1492         r.show();
1493         //assert(r.numele == 0); There are still problems: inaccurate calculations of numele and numnodes.
1494     }
1495 
1496     test1();
1497     test2();
1498 }