mach0data.ic 16.2 KB
Newer Older
1 2
/**********************************************************************
Utilities for converting data from the database file
3
to the machine format.
4 5 6 7 8 9 10 11 12

(c) 1995 Innobase Oy

Created 11/28/1995 Heikki Tuuri
***********************************************************************/

/***********************************************************
The following function is used to store data in one byte. */
UNIV_INLINE
13
void
14 15
mach_write_to_1(
/*============*/
16 17
	byte*	b,	/* in: pointer to byte where to store */
	ulint	n)	/* in: ulint integer to be stored, >= 0, < 256 */
18 19
{
	ut_ad(b);
unknown's avatar
unknown committed
20
	ut_ad(n <= 0xFFUL);
21 22 23 24 25 26 27

	b[0] = (byte)n;
}

/************************************************************
The following function is used to fetch data from one byte. */
UNIV_INLINE
28
ulint
29 30 31
mach_read_from_1(
/*=============*/
			/* out: ulint integer, >= 0, < 256 */
32
	byte*	b)	/* in: pointer to byte */
33 34 35 36 37 38 39 40 41
{
	ut_ad(b);
	return((ulint)(b[0]));
}

/***********************************************************
The following function is used to store data in two consecutive
bytes. We store the most significant byte to the lowest address. */
UNIV_INLINE
42
void
43 44
mach_write_to_2(
/*============*/
45 46
	byte*	b,	/* in: pointer to two bytes where to store */
	ulint	n)	/* in: ulint integer to be stored */
47 48
{
	ut_ad(b);
unknown's avatar
unknown committed
49
	ut_ad(n <= 0xFFFFUL);
50 51 52 53 54 55 56 57 58

	b[0] = (byte)(n >> 8);
	b[1] = (byte)(n);
}

/************************************************************
The following function is used to fetch data from 2 consecutive
bytes. The most significant byte is at the lowest address. */
UNIV_INLINE
59
ulint
60 61 62
mach_read_from_2(
/*=============*/
			/* out: ulint integer */
63
	byte*	b)	/* in: pointer to 2 bytes */
64 65 66 67
{
	ut_ad(b);
	return( ((ulint)(b[0]) << 8)
		+ (ulint)(b[1])
68
	);
69 70
}

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
/************************************************************
The following function is used to convert a 16-bit data item
to the canonical format, for fast bytewise equality test
against memory. */
UNIV_INLINE
uint16
mach_encode_2(
/*==========*/
			/* out: 16-bit integer in canonical format */
	ulint	n)	/* in: integer in machine-dependent format */
{
	uint16	ret;
	ut_ad(2 == sizeof ret);
	mach_write_to_2((byte*) &ret, n);
	return(ret);
}
/************************************************************
The following function is used to convert a 16-bit data item
from the canonical format, for fast bytewise equality test
against memory. */
UNIV_INLINE
ulint
mach_decode_2(
/*==========*/
			/* out: integer in machine-dependent format */
	uint16	n)	/* in: 16-bit integer in canonical format */
{
	ut_ad(2 == sizeof n);
	return(mach_read_from_2((byte*) &n));
}

102 103 104 105
/***********************************************************
The following function is used to store data in 3 consecutive
bytes. We store the most significant byte to the lowest address. */
UNIV_INLINE
106
void
107 108
mach_write_to_3(
/*============*/
109 110
	byte*	b,	/* in: pointer to 3 bytes where to store */
	ulint	n)	/* in: ulint integer to be stored */
111 112
{
	ut_ad(b);
unknown's avatar
unknown committed
113
	ut_ad(n <= 0xFFFFFFUL);
114 115 116 117 118 119 120 121 122 123

	b[0] = (byte)(n >> 16);
	b[1] = (byte)(n >> 8);
	b[2] = (byte)(n);
}

/************************************************************
The following function is used to fetch data from 3 consecutive
bytes. The most significant byte is at the lowest address. */
UNIV_INLINE
124
ulint
125 126 127
mach_read_from_3(
/*=============*/
			/* out: ulint integer */
128
	byte*	b)	/* in: pointer to 3 bytes */
129 130 131 132 133
{
	ut_ad(b);
	return( ((ulint)(b[0]) << 16)
		+ ((ulint)(b[1]) << 8)
		+ (ulint)(b[2])
134
	);
135 136 137 138 139 140
}

/***********************************************************
The following function is used to store data in four consecutive
bytes. We store the most significant byte to the lowest address. */
UNIV_INLINE
141
void
142 143
mach_write_to_4(
/*============*/
144 145
	byte*	b,	/* in: pointer to four bytes where to store */
	ulint	n)	/* in: ulint integer to be stored */
146 147 148
{
	ut_ad(b);

149
#if (0 == 1) && !defined(__STDC__) && defined(UNIV_INTEL) && (UNIV_WORD_SIZE == 4) && defined(UNIV_VISUALC)
150 151 152 153 154 155 156

	/* We do not use this even on Intel, because unaligned accesses may
	be slow */

	__asm	MOV	EAX, n
	__asm	BSWAP	EAX	/* Intel is little-endian, must swap bytes */
	__asm	MOV	n, EAX
157

158 159 160 161 162 163 164 165 166 167 168 169 170
	*((ulint*)b) = n;
#else
	b[0] = (byte)(n >> 24);
	b[1] = (byte)(n >> 16);
	b[2] = (byte)(n >> 8);
	b[3] = (byte)n;
#endif
}

/************************************************************
The following function is used to fetch data from 4 consecutive
bytes. The most significant byte is at the lowest address. */
UNIV_INLINE
171
ulint
172 173 174
mach_read_from_4(
/*=============*/
			/* out: ulint integer */
175
	byte*	b)	/* in: pointer to four bytes */
176
{
177
#if (0 == 1) && !defined(__STDC__) && defined(UNIV_INTEL) && (UNIV_WORD_SIZE == 4) && defined(UNIV_VISUALC)
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
	/* We do not use this even on Intel, because unaligned accesses may
	be slow */

	ulint	res;

	ut_ad(b);

	__asm	MOV	EDX, b
	__asm	MOV	ECX, DWORD PTR [EDX]
	__asm	BSWAP	ECX	/* Intel is little-endian, must swap bytes */
	__asm	MOV	res, ECX

	return(res);
#else
	ut_ad(b);
	return( ((ulint)(b[0]) << 24)
		+ ((ulint)(b[1]) << 16)
		+ ((ulint)(b[2]) << 8)
		+ (ulint)(b[3])
197
	);
198 199 200 201 202 203 204 205
#endif
}

/*************************************************************
Writes a ulint in a compressed form where the first byte codes the
length of the stored ulint. We look at the most significant bits of
the byte. If the most significant bit is zero, it means 1-byte storage,
else if the 2nd bit is 0, it means 2-byte storage, else if 3rd is 0,
206
it means 3-byte storage, else if 4th is 0, it means 4-byte storage,
207 208 209 210 211 212
else the storage is 5-byte. */
UNIV_INLINE
ulint
mach_write_compressed(
/*==================*/
			/* out: compressed size in bytes */
213 214
	byte*	b,	/* in: pointer to memory where to store */
	ulint	n)	/* in: ulint integer (< 2^32) to be stored */
215 216 217
{
	ut_ad(b);

unknown's avatar
unknown committed
218
	if (n < 0x80UL) {
219 220
		mach_write_to_1(b, n);
		return(1);
unknown's avatar
unknown committed
221 222
	} else if (n < 0x4000UL) {
		mach_write_to_2(b, n | 0x8000UL);
223
		return(2);
unknown's avatar
unknown committed
224 225
	} else if (n < 0x200000UL) {
		mach_write_to_3(b, n | 0xC00000UL);
226
		return(3);
unknown's avatar
unknown committed
227 228
	} else if (n < 0x10000000UL) {
		mach_write_to_4(b, n | 0xE0000000UL);
229 230
		return(4);
	} else {
unknown's avatar
unknown committed
231
		mach_write_to_1(b, 0xF0UL);
232 233 234 235 236 237 238 239 240 241 242 243
		mach_write_to_4(b + 1, n);
		return(5);
	}
}

/*************************************************************
Returns the size of a ulint when written in the compressed form. */
UNIV_INLINE
ulint
mach_get_compressed_size(
/*=====================*/
			/* out: compressed size in bytes */
244
	ulint	n)	/* in: ulint integer (< 2^32) to be stored */
245
{
unknown's avatar
unknown committed
246
	if (n < 0x80UL) {
247
		return(1);
unknown's avatar
unknown committed
248
	} else if (n < 0x4000UL) {
249
		return(2);
unknown's avatar
unknown committed
250
	} else if (n < 0x200000UL) {
251
		return(3);
unknown's avatar
unknown committed
252
	} else if (n < 0x10000000UL) {
253 254 255 256 257 258 259 260 261 262 263 264 265
		return(4);
	} else {
		return(5);
	}
}

/*************************************************************
Reads a ulint in a compressed form. */
UNIV_INLINE
ulint
mach_read_compressed(
/*=================*/
			/* out: read integer (< 2^32) */
266
	byte*	b)	/* in: pointer to memory from where to read */
267 268 269 270 271 272 273
{
	ulint	flag;

	ut_ad(b);

	flag = mach_read_from_1(b);

unknown's avatar
unknown committed
274
	if (flag < 0x80UL) {
275
		return(flag);
unknown's avatar
unknown committed
276 277 278 279 280 281
	} else if (flag < 0xC0UL) {
		return(mach_read_from_2(b) & 0x7FFFUL);
	} else if (flag < 0xE0UL) {
		return(mach_read_from_3(b) & 0x3FFFFFUL);
	} else if (flag < 0xF0UL) {
		return(mach_read_from_4(b) & 0x1FFFFFFFUL);
282
	} else {
unknown's avatar
unknown committed
283
		ut_ad(flag == 0xF0UL);
284 285 286 287 288 289 290 291
		return(mach_read_from_4(b + 1));
	}
}

/***********************************************************
The following function is used to store data in 8 consecutive
bytes. We store the most significant byte to the lowest address. */
UNIV_INLINE
292
void
293 294
mach_write_to_8(
/*============*/
295 296
	byte*	b,	/* in: pointer to 8 bytes where to store */
	dulint	n)	/* in: dulint integer to be stored */
297 298 299 300 301 302 303 304 305 306 307
{
	ut_ad(b);

	mach_write_to_4(b, ut_dulint_get_high(n));
	mach_write_to_4(b + 4, ut_dulint_get_low(n));
}

/************************************************************
The following function is used to fetch data from 8 consecutive
bytes. The most significant byte is at the lowest address. */
UNIV_INLINE
308
dulint
309 310 311
mach_read_from_8(
/*=============*/
			/* out: dulint integer */
312
	byte*	b)	/* in: pointer to 8 bytes */
313 314 315 316 317 318 319 320 321
{
	ulint	high;
	ulint	low;

	ut_ad(b);

	high = mach_read_from_4(b);
	low = mach_read_from_4(b + 4);

322
	return(ut_dulint_create(high, low));
323 324 325 326 327 328
}

/***********************************************************
The following function is used to store data in 7 consecutive
bytes. We store the most significant byte to the lowest address. */
UNIV_INLINE
329
void
330 331
mach_write_to_7(
/*============*/
332 333
	byte*	b,	/* in: pointer to 7 bytes where to store */
	dulint	n)	/* in: dulint integer to be stored */
334 335 336 337 338 339 340 341 342 343 344
{
	ut_ad(b);

	mach_write_to_3(b, ut_dulint_get_high(n));
	mach_write_to_4(b + 3, ut_dulint_get_low(n));
}

/************************************************************
The following function is used to fetch data from 7 consecutive
bytes. The most significant byte is at the lowest address. */
UNIV_INLINE
345
dulint
346 347 348
mach_read_from_7(
/*=============*/
			/* out: dulint integer */
349
	byte*	b)	/* in: pointer to 7 bytes */
350 351 352 353 354 355 356 357 358
{
	ulint	high;
	ulint	low;

	ut_ad(b);

	high = mach_read_from_3(b);
	low = mach_read_from_4(b + 3);

359
	return(ut_dulint_create(high, low));
360 361 362 363 364 365
}

/***********************************************************
The following function is used to store data in 6 consecutive
bytes. We store the most significant byte to the lowest address. */
UNIV_INLINE
366
void
367 368
mach_write_to_6(
/*============*/
369 370
	byte*	b,	/* in: pointer to 6 bytes where to store */
	dulint	n)	/* in: dulint integer to be stored */
371 372 373 374 375 376 377 378 379 380 381
{
	ut_ad(b);

	mach_write_to_2(b, ut_dulint_get_high(n));
	mach_write_to_4(b + 2, ut_dulint_get_low(n));
}

/************************************************************
The following function is used to fetch data from 6 consecutive
bytes. The most significant byte is at the lowest address. */
UNIV_INLINE
382
dulint
383 384 385
mach_read_from_6(
/*=============*/
			/* out: dulint integer */
386
	byte*	b)	/* in: pointer to 7 bytes */
387 388 389 390 391 392 393 394 395
{
	ulint	high;
	ulint	low;

	ut_ad(b);

	high = mach_read_from_2(b);
	low = mach_read_from_4(b + 2);

396
	return(ut_dulint_create(high, low));
397 398 399
}

/*************************************************************
unknown's avatar
unknown committed
400
Writes a dulint in a compressed form (5..9 bytes). */
401 402 403 404 405
UNIV_INLINE
ulint
mach_dulint_write_compressed(
/*=========================*/
			/* out: size in bytes */
406 407
	byte*	b,	/* in: pointer to memory where to store */
	dulint	n)	/* in: dulint integer to be stored */
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
{
	ulint	size;

	ut_ad(b);

	size = mach_write_compressed(b, ut_dulint_get_high(n));
	mach_write_to_4(b + size, ut_dulint_get_low(n));

	return(size + 4);
}

/*************************************************************
Returns the size of a dulint when written in the compressed form. */
UNIV_INLINE
ulint
mach_dulint_get_compressed_size(
/*============================*/
			/* out: compressed size in bytes */
426
	dulint	 n)	/* in: dulint integer to be stored */
427 428 429 430 431 432 433 434 435 436 437
{
	return(4 + mach_get_compressed_size(ut_dulint_get_high(n)));
}

/*************************************************************
Reads a dulint in a compressed form. */
UNIV_INLINE
dulint
mach_dulint_read_compressed(
/*========================*/
			/* out: read dulint */
438
	byte*	b)	/* in: pointer to memory from where to read */
439 440 441 442 443 444 445 446 447 448 449 450 451
{
	ulint	high;
	ulint	low;
	ulint	size;

	ut_ad(b);

	high = mach_read_compressed(b);

	size = mach_get_compressed_size(high);

	low = mach_read_from_4(b + size);

452
	return(ut_dulint_create(high, low));
453 454 455
}

/*************************************************************
unknown's avatar
unknown committed
456
Writes a dulint in a compressed form (1..11 bytes). */
457 458 459 460 461
UNIV_INLINE
ulint
mach_dulint_write_much_compressed(
/*==============================*/
			/* out: size in bytes */
462 463
	byte*	b,	/* in: pointer to memory where to store */
	dulint	n)	/* in: dulint integer to be stored */
464 465 466 467
{
	ulint	size;

	ut_ad(b);
468

469 470 471
	if (ut_dulint_get_high(n) == 0) {
		return(mach_write_compressed(b, ut_dulint_get_low(n)));
	}
472

unknown's avatar
unknown committed
473
	*b = (byte)0xFF;
474 475 476 477 478 479 480 481 482 483 484 485 486 487
	size = 1 + mach_write_compressed(b + 1, ut_dulint_get_high(n));

	size += mach_write_compressed(b + size, ut_dulint_get_low(n));

	return(size);
}

/*************************************************************
Returns the size of a dulint when written in the compressed form. */
UNIV_INLINE
ulint
mach_dulint_get_much_compressed_size(
/*=================================*/
			/* out: compressed size in bytes */
488
	dulint	 n)	/* in: dulint integer to be stored */
489 490 491 492 493 494
{
	if (0 == ut_dulint_get_high(n)) {
		return(mach_get_compressed_size(ut_dulint_get_low(n)));
	}

	return(1 + mach_get_compressed_size(ut_dulint_get_high(n))
495
		+ mach_get_compressed_size(ut_dulint_get_low(n)));
496 497 498 499 500 501 502 503 504
}

/*************************************************************
Reads a dulint in a compressed form. */
UNIV_INLINE
dulint
mach_dulint_read_much_compressed(
/*=============================*/
			/* out: read dulint */
505
	byte*	b)	/* in: pointer to memory from where to read */
506 507 508 509 510 511 512
{
	ulint	high;
	ulint	low;
	ulint	size;

	ut_ad(b);

unknown's avatar
unknown committed
513
	if (*b != (byte)0xFF) {
514 515 516 517 518 519 520 521 522 523
		high = 0;
		size = 0;
	} else {
		high = mach_read_compressed(b + 1);

		size = 1 + mach_get_compressed_size(high);
	}

	low = mach_read_compressed(b + size);

524
	return(ut_dulint_create(high, low));
525 526 527 528 529 530 531 532 533
}

/*************************************************************
Reads a double. It is stored in a little-endian format. */
UNIV_INLINE
double
mach_double_read(
/*=============*/
			/* out: double read */
534
	byte*	b)	/* in: pointer to memory from where to read */
535
{
536
	double	d;
537 538 539 540 541 542 543 544 545 546 547 548 549
	ulint	i;
	byte*	ptr;

	ptr = (byte*)&d;

	for (i = 0; i < sizeof(double); i++) {
#ifdef WORDS_BIGENDIAN
		ptr[sizeof(double) - i - 1] = b[i];
#else
		ptr[i] = b[i];
#endif
	}

550
	return(d);
551 552 553 554 555 556 557 558
}

/*************************************************************
Writes a double. It is stored in a little-endian format. */
UNIV_INLINE
void
mach_double_write(
/*==============*/
559 560
	byte*	b,	/* in: pointer to memory where to write */
	double	d)	/* in: double */
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
{
	ulint	i;
	byte*	ptr;

	ptr = (byte*)&d;

	for (i = 0; i < sizeof(double); i++) {
#ifdef WORDS_BIGENDIAN
		b[i] = ptr[sizeof(double) - i - 1];
#else
		b[i] = ptr[i];
#endif
	}
}

/*************************************************************
Reads a float. It is stored in a little-endian format. */
UNIV_INLINE
float
mach_float_read(
581
/*============*/
582
			/* out: float read */
583
	byte*	b)	/* in: pointer to memory from where to read */
584
{
585
	float	d;
586 587 588 589 590 591 592 593 594 595 596 597 598
	ulint	i;
	byte*	ptr;

	ptr = (byte*)&d;

	for (i = 0; i < sizeof(float); i++) {
#ifdef WORDS_BIGENDIAN
		ptr[sizeof(float) - i - 1] = b[i];
#else
		ptr[i] = b[i];
#endif
	}

599
	return(d);
600 601 602 603 604 605 606
}

/*************************************************************
Writes a float. It is stored in a little-endian format. */
UNIV_INLINE
void
mach_float_write(
607 608 609
/*=============*/
	byte*	b,	/* in: pointer to memory where to write */
	float	d)	/* in: float */
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
{
	ulint	i;
	byte*	ptr;

	ptr = (byte*)&d;

	for (i = 0; i < sizeof(float); i++) {
#ifdef WORDS_BIGENDIAN
		b[i] = ptr[sizeof(float) - i - 1];
#else
		b[i] = ptr[i];
#endif
	}
}

/*************************************************************
Reads a ulint stored in the little-endian format. */
UNIV_INLINE
ulint
mach_read_from_n_little_endian(
/*===========================*/
				/* out: unsigned long int */
	byte*	buf,		/* in: from where to read */
	ulint	buf_size)	/* in: from how many bytes to read */
{
	ulint	n	= 0;
	byte*	ptr;

	ut_ad(buf_size <= sizeof(ulint));
	ut_ad(buf_size > 0);

	ptr = buf + buf_size;
642

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
	for (;;) {
		ptr--;

		n = n << 8;

		n += (ulint)(*ptr);

		if (ptr == buf) {
			break;
		}
	}

	return(n);
}

/*************************************************************
Writes a ulint in the little-endian format. */
UNIV_INLINE
void
mach_write_to_n_little_endian(
/*==========================*/
	byte*	dest,		/* in: where to write */
	ulint	dest_size,	/* in: into how many bytes to write */
	ulint	n)		/* in: unsigned long int to write */
{
	byte*	end;

	ut_ad(dest_size <= sizeof(ulint));
	ut_ad(dest_size > 0);

	end = dest + dest_size;
674

675 676 677 678 679 680 681 682 683
	for (;;) {
		*dest = (byte)(n & 0xFF);

		n = n >> 8;

		dest++;

		if (dest == end) {
			break;
684
		}
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
	}

	ut_ad(n == 0);
}

/*************************************************************
Reads a ulint stored in the little-endian format. */
UNIV_INLINE
ulint
mach_read_from_2_little_endian(
/*===========================*/
				/* out: unsigned long int */
	byte*	buf)		/* in: from where to read */
{
	return((ulint)(*buf) + ((ulint)(*(buf + 1))) * 256);
}

/*************************************************************
Writes a ulint in the little-endian format. */
UNIV_INLINE
void
mach_write_to_2_little_endian(
/*==========================*/
	byte*	dest,		/* in: where to write */
	ulint	n)		/* in: unsigned long int to write */
{
	ut_ad(n < 256 * 256);

unknown's avatar
unknown committed
713
	*dest = (byte)(n & 0xFFUL);
714 715 716 717

	n = n >> 8;
	dest++;

unknown's avatar
unknown committed
718
	*dest = (byte)(n & 0xFFUL);
719
}