1/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16/*
17 get_ptr_compare(len) returns a pointer to a optimal byte-compare function
18 for a array of stringpointer where all strings have size len.
19 The bytes are compare as unsigned chars.
20 */
21
22#include "mysys_priv.h"
23#include <myisampack.h>
24/*
25 * On some platforms, memcmp() is faster than the unrolled ptr_compare_N
26 * functions, as memcmp() is usually a platform-specific implementation
27 * written in assembler. for example one in /usr/lib/libc/libc_hwcap*.so.1.
28 * on Solaris, or on Windows inside C runtime linrary.
29 *
30 * On Solaris, native implementation is also usually faster than the
31 * built-in memcmp supplied by GCC, so it is recommended to build
32 * with "-fno-builtin-memcmp"in CFLAGS if building with GCC on Solaris.
33 */
34
35/*
36 Daniel Blacks tests shows that libc memcmp is generally faster than
37 ptr_cmp() at least of x86 and power8 platforms, so we use the libc
38 code as deafult for now
39*/
40
41#define USE_NATIVE_MEMCMP 1
42
43#ifdef USE_NATIVE_MEMCMP
44
45#include <string.h>
46
47static int native_compare(size_t *length, unsigned char **a, unsigned char **b)
48{
49 return memcmp(*a, *b, *length);
50}
51
52qsort2_cmp get_ptr_compare (size_t size __attribute__((unused)))
53{
54 return (qsort2_cmp) native_compare;
55}
56
57#else /* USE_NATIVE_MEMCMP */
58
59static int ptr_compare(size_t *compare_length, uchar **a, uchar **b);
60static int ptr_compare_0(size_t *compare_length, uchar **a, uchar **b);
61static int ptr_compare_1(size_t *compare_length, uchar **a, uchar **b);
62static int ptr_compare_2(size_t *compare_length, uchar **a, uchar **b);
63static int ptr_compare_3(size_t *compare_length, uchar **a, uchar **b);
64
65qsort2_cmp get_ptr_compare (size_t size)
66{
67 if (size < 4)
68 return (qsort2_cmp) ptr_compare;
69 switch (size & 3) {
70 case 0: return (qsort2_cmp) ptr_compare_0;
71 case 1: return (qsort2_cmp) ptr_compare_1;
72 case 2: return (qsort2_cmp) ptr_compare_2;
73 case 3: return (qsort2_cmp) ptr_compare_3;
74 }
75 return 0; /* Impossible */
76}
77 /*
78 Compare to keys to see witch is smaller.
79 Loop unrolled to make it quick !!
80 */
81
82#define cmp(N) if (first[N] != last[N]) return (int) first[N] - (int) last[N]
83
84static int ptr_compare(size_t *compare_length, uchar **a, uchar **b)
85{
86 size_t length= *compare_length;
87 uchar *first,*last;
88
89 DBUG_ASSERT(length > 0);
90 first= *a; last= *b;
91 while (--length)
92 {
93 if (*first++ != *last++)
94 return (int) first[-1] - (int) last[-1];
95 }
96 return (int) first[0] - (int) last[0];
97}
98
99
100static int ptr_compare_0(size_t *compare_length,uchar **a, uchar **b)
101{
102 size_t length= *compare_length;
103 uchar *first,*last;
104
105 first= *a; last= *b;
106 loop:
107 cmp(0);
108 cmp(1);
109 cmp(2);
110 cmp(3);
111 if ((length-=4))
112 {
113 first+=4;
114 last+=4;
115 goto loop;
116 }
117 return (0);
118}
119
120
121static int ptr_compare_1(size_t *compare_length,uchar **a, uchar **b)
122{
123 size_t length= *compare_length-1;
124 uchar *first,*last;
125
126 first= *a+1; last= *b+1;
127 cmp(-1);
128 loop:
129 cmp(0);
130 cmp(1);
131 cmp(2);
132 cmp(3);
133 if ((length-=4))
134 {
135 first+=4;
136 last+=4;
137 goto loop;
138 }
139 return (0);
140}
141
142static int ptr_compare_2(size_t *compare_length,uchar **a, uchar **b)
143{
144 size_t length= *compare_length-2;
145 uchar *first,*last;
146
147 first= *a +2 ; last= *b +2;
148 cmp(-2);
149 cmp(-1);
150 loop:
151 cmp(0);
152 cmp(1);
153 cmp(2);
154 cmp(3);
155 if ((length-=4))
156 {
157 first+=4;
158 last+=4;
159 goto loop;
160 }
161 return (0);
162}
163
164static int ptr_compare_3(size_t *compare_length,uchar **a, uchar **b)
165{
166 size_t length= *compare_length-3;
167 uchar *first,*last;
168
169 first= *a +3 ; last= *b +3;
170 cmp(-3);
171 cmp(-2);
172 cmp(-1);
173 loop:
174 cmp(0);
175 cmp(1);
176 cmp(2);
177 cmp(3);
178 if ((length-=4))
179 {
180 first+=4;
181 last+=4;
182 goto loop;
183 }
184 return (0);
185}
186
187#endif /* USE_NATIVE_MEMCMP */
188
189void my_store_ptr(uchar *buff, size_t pack_length, my_off_t pos)
190{
191 switch (pack_length) {
192#if SIZEOF_OFF_T > 4
193 case 8: mi_int8store(buff,pos); break;
194 case 7: mi_int7store(buff,pos); break;
195 case 6: mi_int6store(buff,pos); break;
196 case 5: mi_int5store(buff,pos); break;
197#endif
198 case 4: mi_int4store(buff,pos); break;
199 case 3: mi_int3store(buff,pos); break;
200 case 2: mi_int2store(buff,pos); break;
201 case 1: buff[0]= (uchar) pos; break;
202 default: DBUG_ASSERT(0);
203 }
204 return;
205}
206
207my_off_t my_get_ptr(uchar *ptr, size_t pack_length)
208{
209 my_off_t pos;
210 switch (pack_length) {
211#if SIZEOF_OFF_T > 4
212 case 8: pos= (my_off_t) mi_uint8korr(ptr); break;
213 case 7: pos= (my_off_t) mi_uint7korr(ptr); break;
214 case 6: pos= (my_off_t) mi_uint6korr(ptr); break;
215 case 5: pos= (my_off_t) mi_uint5korr(ptr); break;
216#endif
217 case 4: pos= (my_off_t) mi_uint4korr(ptr); break;
218 case 3: pos= (my_off_t) mi_uint3korr(ptr); break;
219 case 2: pos= (my_off_t) mi_uint2korr(ptr); break;
220 case 1: pos= (my_off_t) *(uchar*) ptr; break;
221 default: DBUG_ASSERT(0); return 0;
222 }
223 return pos;
224}
225