/*****************************************************************************

Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA

*****************************************************************************/

/******************************************************************//**
@file include/mach0data.h
Utilities for converting data from the database file
to the machine format.

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

#ifndef mach0data_h
#define mach0data_h

#include "univ.i"
#include "mtr0types.h"

#ifndef UNIV_INNOCHECKSUM

/* The data and all fields are always stored in a database file
in the same format: ascii, big-endian, ... .
All data in the files MUST be accessed using the functions in this
module. */

/*******************************************************//**
The following function is used to store data in one byte. */
inline __attribute__((always_inline))
void
mach_write_to_1(
/*============*/
	byte*	b,	/*!< in: pointer to byte where to store */
	ulint	n);	 /*!< in: ulint integer to be stored, >= 0, < 256 */
/** The following function is used to fetch data from one byte.
@param[in]	b	pointer to a byte to read
@return ulint integer, >= 0, < 256 */
inline __attribute__((always_inline))
uint8_t
mach_read_from_1(
	const byte*	b)
	MY_ATTRIBUTE((warn_unused_result));
/*******************************************************//**
The following function is used to store data in two consecutive
bytes. We store the most significant byte to the lower address. */
inline __attribute__((always_inline))
void
mach_write_to_2(
/*============*/
	byte*	b,	/*!< in: pointer to two bytes where to store */
	ulint	n);	 /*!< in: ulint integer to be stored, >= 0, < 64k */
#endif /* !UNIV_INNOCHECKSUM */
/** The following function is used to fetch data from 2 consecutive
bytes. The most significant byte is at the lowest address.
@param[in]	b	pointer to 2 bytes where to store
@return 2-byte integer, >= 0, < 64k */
inline __attribute__((always_inline))
uint16_t
mach_read_from_2(
	const byte*	b)
	MY_ATTRIBUTE((warn_unused_result));

#ifndef UNIV_INNOCHECKSUM
/********************************************************//**
The following function is used to convert a 16-bit data item
to the canonical format, for fast bytewise equality test
against memory.
@return 16-bit integer in canonical format */
inline __attribute__((always_inline))
uint16
mach_encode_2(
/*==========*/
	ulint	n)	/*!< in: integer in machine-dependent format */
	MY_ATTRIBUTE((const));
/********************************************************//**
The following function is used to convert a 16-bit data item
from the canonical format, for fast bytewise equality test
against memory.
@return integer in machine-dependent format */
inline __attribute__((always_inline))
ulint
mach_decode_2(
/*==========*/
	uint16	n)	/*!< in: 16-bit integer in canonical format */
	MY_ATTRIBUTE((const));
/*******************************************************//**
The following function is used to store data in 3 consecutive
bytes. We store the most significant byte to the lowest address. */
UNIV_INLINE
void
mach_write_to_3(
/*============*/
	byte*	b,	/*!< in: pointer to 3 bytes where to store */
	ulint	n);	 /*!< in: ulint integer to be stored */
/** The following function is used to fetch data from 3 consecutive
bytes. The most significant byte is at the lowest address.
@param[in]	b	pointer to 3 bytes to read
@return 32 bit integer */
UNIV_INLINE
uint32_t
mach_read_from_3(
	const byte*	b)
	MY_ATTRIBUTE((warn_unused_result));
/*******************************************************//**
The following function is used to store data in four consecutive
bytes. We store the most significant byte to the lowest address. */
inline __attribute__((always_inline))
void
mach_write_to_4(
/*============*/
	byte*	b,	/*!< in: pointer to four bytes where to store */
	ulint	n);	 /*!< in: ulint integer to be stored */
/** The following function is used to fetch data from 4 consecutive
bytes. The most significant byte is at the lowest address.
@param[in]	b	pointer to 4 bytes to read
@return 32 bit integer */
inline __attribute__((always_inline))
uint32_t
mach_read_from_4(
	const byte*	b)
	MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a ulint in a compressed form (1..5 bytes).
@return stored size in bytes */
UNIV_INLINE
ulint
mach_write_compressed(
/*==================*/
	byte*	b,	/*!< in: pointer to memory where to store */
	ulint	n);	/*!< in: ulint integer to be stored */
/*********************************************************//**
Returns the size of an ulint when written in the compressed form.
@return compressed size in bytes */
UNIV_INLINE
ulint
mach_get_compressed_size(
/*=====================*/
	ulint	n)	/*!< in: ulint integer to be stored */
	MY_ATTRIBUTE((const));
/** Read a 32-bit integer in a compressed form.
@param[in,out]	b	pointer to memory where to read;
advanced by the number of bytes consumed
@return unsigned value */
UNIV_INLINE
ib_uint32_t
mach_read_next_compressed(
	const byte**	b);
/*******************************************************//**
The following function is used to store data in 6 consecutive
bytes. We store the most significant byte to the lowest address. */
UNIV_INLINE
void
mach_write_to_6(
/*============*/
	byte*		b,	/*!< in: pointer to 6 bytes where to store */
	ib_uint64_t	id);	/*!< in: 48-bit integer */
/********************************************************//**
The following function is used to fetch data from 6 consecutive
bytes. The most significant byte is at the lowest address.
@return 48-bit integer */
UNIV_INLINE
ib_uint64_t
mach_read_from_6(
/*=============*/
	const byte*	b)	/*!< in: pointer to 6 bytes */
	MY_ATTRIBUTE((warn_unused_result));
/*******************************************************//**
The following function is used to store data in 7 consecutive
bytes. We store the most significant byte to the lowest address. */
UNIV_INLINE
void
mach_write_to_7(
/*============*/
	byte*		b,	/*!< in: pointer to 7 bytes where to store */
	ib_uint64_t	n);	/*!< in: 56-bit integer */
/********************************************************//**
The following function is used to fetch data from 7 consecutive
bytes. The most significant byte is at the lowest address.
@return 56-bit integer */
UNIV_INLINE
ib_uint64_t
mach_read_from_7(
/*=============*/
	const byte*	b)	/*!< in: pointer to 7 bytes */
	MY_ATTRIBUTE((warn_unused_result));
/*******************************************************//**
The following function is used to store data in 8 consecutive
bytes. We store the most significant byte to the lowest address. */
inline __attribute__((always_inline))
void
mach_write_to_8(
/*============*/
	void*		b,	/*!< in: pointer to 8 bytes where to store */
	ib_uint64_t	n);	/*!< in: 64-bit integer to be stored */
/********************************************************//**
The following function is used to fetch data from 8 consecutive
bytes. The most significant byte is at the lowest address.
@return 64-bit integer */
inline __attribute__((always_inline))
ib_uint64_t
mach_read_from_8(
/*=============*/
	const byte*	b)	/*!< in: pointer to 8 bytes */
	MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a 64-bit integer in a compressed form (5..9 bytes).
@return size in bytes */
UNIV_INLINE
ulint
mach_u64_write_compressed(
/*======================*/
	byte*		b,	/*!< in: pointer to memory where to store */
	ib_uint64_t	n);	/*!< in: 64-bit integer to be stored */
/** Read a 64-bit integer in a compressed form.
@param[in,out]	b	pointer to memory where to read;
advanced by the number of bytes consumed
@return unsigned value */
UNIV_INLINE
ib_uint64_t
mach_u64_read_next_compressed(
	const byte**	b);
/*********************************************************//**
Writes a 64-bit integer in a compressed form (1..11 bytes).
@return size in bytes */
UNIV_INLINE
ulint
mach_u64_write_much_compressed(
/*===========================*/
	byte*		b,	/*!< in: pointer to memory where to store */
	ib_uint64_t	n);	/*!< in: 64-bit integer to be stored */
/*********************************************************//**
Reads a 64-bit integer in a compressed form.
@return the value read */
UNIV_INLINE
ib_uint64_t
mach_u64_read_much_compressed(
/*==========================*/
	const byte*	b)	/*!< in: pointer to memory from where to read */
	MY_ATTRIBUTE((warn_unused_result));

/*********************************************************//**
Reads a double. It is stored in a little-endian format.
@return double read */
UNIV_INLINE
double
mach_double_read(
/*=============*/
	const byte*	b)	/*!< in: pointer to memory from where to read */
	MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a double. It is stored in a little-endian format. */
UNIV_INLINE
void
mach_double_write(
/*==============*/
	byte*	b,	/*!< in: pointer to memory where to write */
	double	d);	/*!< in: double */
/*********************************************************//**
Reads a float. It is stored in a little-endian format.
@return float read */
UNIV_INLINE
float
mach_float_read(
/*============*/
	const byte*	b)	/*!< in: pointer to memory from where to read */
	MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a float. It is stored in a little-endian format. */
UNIV_INLINE
void
mach_float_write(
/*=============*/
	byte*	b,	/*!< in: pointer to memory where to write */
	float	d);	/*!< in: float */
/*********************************************************//**
Reads a ulint stored in the little-endian format.
@return unsigned long int */
UNIV_INLINE
ulint
mach_read_from_n_little_endian(
/*===========================*/
	const byte*	buf,		/*!< in: from where to read */
	ulint		buf_size)	/*!< in: from how many bytes to read */
	MY_ATTRIBUTE((warn_unused_result));


/** Reads a 64 bit stored in big endian format
@param	buf		From where to read
@return uint64_t */
inline __attribute__((always_inline))
uint64_t
mach_read_uint64_little_endian(const byte* buf)
{
#ifdef WORDS_BIGENDIAN
  return
    uint64_t(buf[0])       | uint64_t(buf[1]) << 8 |
    uint64_t(buf[2]) << 16 | uint64_t(buf[3]) << 24 |
    uint64_t(buf[4]) << 32 | uint64_t(buf[5]) << 40 |
    uint64_t(buf[6]) << 48 | uint64_t(buf[7]) << 56;
#else
  uint64_t n;
  memcpy(&n, buf, sizeof(uint64_t));
  return n;
#endif
}

/*********************************************************//**
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 */
/*********************************************************//**
Reads a ulint stored in the little-endian format.
@return unsigned long int */
inline __attribute__((always_inline))
ulint
mach_read_from_2_little_endian(
/*===========================*/
	const byte*	buf)		/*!< in: from where to read */
	MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a ulint in the little-endian format. */
inline __attribute__((always_inline))
void
mach_write_to_2_little_endian(
/*==========================*/
	byte*	dest,		/*!< in: where to write */
	ulint	n);		/*!< in: unsigned long int to write */
/*********************************************************//**
Convert integral type from storage byte order (big endian) to
host byte order.
@return integer value */
UNIV_INLINE
ib_uint64_t
mach_read_int_type(
/*===============*/
	const byte*	src,		/*!< in: where to read from */
	ulint		len,		/*!< in: length of src */
	ibool		unsigned_type);	/*!< in: signed or unsigned flag */

/*************************************************************
Convert a ulonglong integer from host byte order to (big-endian)
storage byte order. */
UNIV_INLINE
void
mach_write_ulonglong(
/*=================*/
	byte*		dest,		/*!< in: where to write */
	ulonglong	src,		/*!< in: where to read from */
	ulint		len,		/*!< in: length of dest */
	bool		usign);		/*!< in: signed or unsigned flag */

#endif /* !UNIV_INNOCHECKSUM */

#include "mach0data.inl"

#endif
