summaryrefslogtreecommitdiff
path: root/mpz/out_raw.c
diff options
context:
space:
mode:
authorKevin Ryde <user42@zip.com.au>2001-12-21 18:37:59 +0100
committerKevin Ryde <user42@zip.com.au>2001-12-21 18:37:59 +0100
commite52c2465a48ebfcf8101a1d1b3d7a503b4bdf113 (patch)
tree296bee8778db700eb60bd783bfda683a6959245e /mpz/out_raw.c
parent9df5ffa985b2cf169176a6faacc3c28b15c2cb6f (diff)
downloadgmp-e52c2465a48ebfcf8101a1d1b3d7a503b4bdf113.tar.gz
* mpz/inp_raw.c, mpz/out_raw.c: Rewrite.
Diffstat (limited to 'mpz/out_raw.c')
-rw-r--r--mpz/out_raw.c173
1 files changed, 118 insertions, 55 deletions
diff --git a/mpz/out_raw.c b/mpz/out_raw.c
index f5f071252..dc5591e5a 100644
--- a/mpz/out_raw.c
+++ b/mpz/out_raw.c
@@ -1,7 +1,6 @@
-/* mpz_out_raw -- Output a mpz_t in binary. Use an endianess and word size
- independent format.
+/* mpz_out_raw -- write an mpz_t in raw format.
-Copyright 1995, 2001 Free Software Foundation, Inc.
+Copyright 2001 Free Software Foundation, Inc.
This file is part of the GNU MP Library.
@@ -21,66 +20,130 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA. */
#include <stdio.h>
-
#include "gmp.h"
#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* HTON_LIMB_STORE takes a normal host byte order limb and stores it as
+ network byte order (ie. big endian). */
+
+#if HAVE_BIG_ENDIAN
+#define HTON_LIMB_STORE(dst, limb) do { *(dst) = (limb); } while (0)
+#endif
+
+/* The generic implementations below very likely come out as lots of
+ separate byte stores, so if we know the host is little endian then
+ instead use a purely arithmetic BSWAP_LIMB and a single store. */
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define HTON_LIMB_STORE(dst, limb) BSWAP_LIMB (*dst, limb)
+#endif
+
+#if ! defined (HTON_LIMB_STORE)
+#if BITS_PER_MP_LIMB == 8
+#define HTON_LIMB_STORE(dst, limb) do { *(dst) = (limb); } while (0)
+#endif
+#if BITS_PER_MP_LIMB == 16
+#define HTON_LIMB_STORE(dst, limb) \
+ do { \
+ mp_limb_t __limb = (limb); \
+ char *__p = (char *) (dst); \
+ __p[1] = (__limb); \
+ __p[0] = (__limb) >> 8; \
+ } while (0)
+#endif
+#if BITS_PER_MP_LIMB == 32
+#define HTON_LIMB_STORE(dst, limb) \
+ do { \
+ mp_limb_t __limb = (limb); \
+ char *__p = (char *) (dst); \
+ __p[3] = (__limb); \
+ __p[2] = (__limb) >> 8; \
+ __p[1] = (__limb) >> 16; \
+ __p[0] = (__limb) >> 24; \
+ } while (0)
+#endif
+#if BITS_PER_MP_LIMB == 64
+#define HTON_LIMB_STORE(dst, limb) \
+ do { \
+ mp_limb_t __limb = (limb); \
+ char *__p = (char *) (dst); \
+ __p[7] = (__limb); \
+ __p[6] = (__limb) >> 8; \
+ __p[5] = (__limb) >> 16; \
+ __p[4] = (__limb) >> 24; \
+ __p[3] = (__limb) >> 32; \
+ __p[2] = (__limb) >> 40; \
+ __p[1] = (__limb) >> 48; \
+ __p[0] = (__limb) >> 56; \
+ } while (0)
+#endif
+#endif
-#define BITS_PER_CHAR 8
-
size_t
-mpz_out_raw (FILE *stream, mpz_srcptr x)
+mpz_out_raw (FILE *fp, mpz_srcptr x)
{
- int i;
- mp_size_t s;
- mp_size_t xsize = ABS (x->_mp_size);
- mp_srcptr xp = x->_mp_d;
- mp_size_t out_bytesize;
- mp_limb_t hi_limb;
- int n_bytes_in_hi_limb;
-
- if (stream == 0)
- stream = stdout;
-
- if (xsize == 0)
+ mp_size_t xsize, abs_xsize, bytes, i;
+ mp_srcptr xp;
+ char *tp, *bp;
+ mp_limb_t xlimb;
+ int zeros;
+ size_t tsize, ssize;
+
+ xsize = SIZ(x);
+ abs_xsize = ABS (xsize);
+ bytes = BYTES_PER_MP_LIMB * abs_xsize;
+ tsize = ROUND_UP_MULTIPLE (4, BYTES_PER_MP_LIMB) + bytes;
+
+ tp = (*__gmp_allocate_func) (tsize);
+ bp = tp + ROUND_UP_MULTIPLE (4, BYTES_PER_MP_LIMB);
+
+ if (bytes != 0)
{
- for (i = 4 - 1; i >= 0; i--)
- fputc (0, stream);
- return ferror (stream) ? 0 : 4;
+ /* reverse limb order, and byte swap if necessary */
+ bp += bytes;
+ xp = PTR (x);
+ i = abs_xsize;
+#ifdef _CRAY
+ _Pragma ("_CRI ivdep");
+#endif
+ do
+ {
+ bp -= BYTES_PER_MP_LIMB;
+ xlimb = *xp;
+ HTON_LIMB_STORE ((mp_ptr) bp, xlimb);
+ xp++;
+ }
+ while (--i > 0);
+
+ /* strip high zero bytes (without fetching from bp) */
+ count_leading_zeros (zeros, xlimb);
+ zeros /= 8;
+ bp += zeros;
+ bytes -= zeros;
}
- hi_limb = xp[xsize - 1];
- for (i = BYTES_PER_MP_LIMB - 1; i > 0; i--)
- {
- if ((hi_limb >> i * BITS_PER_CHAR) != 0)
- break;
- }
- n_bytes_in_hi_limb = i + 1;
- out_bytesize = BYTES_PER_MP_LIMB * (xsize - 1) + n_bytes_in_hi_limb;
- if (x->_mp_size < 0)
- out_bytesize = -out_bytesize;
-
- /* Make the size 4 bytes on all machines, to make the format portable. */
- for (i = 4 - 1; i >= 0; i--)
- fputc ((out_bytesize >> (i * BITS_PER_CHAR)) % (1 << BITS_PER_CHAR),
- stream);
-
- /* Output from the most significant limb to the least significant limb,
- with each limb also output in decreasing significance order. */
-
- /* Output the most significant limb separately, since we will only
- output some of its bytes. */
- for (i = n_bytes_in_hi_limb - 1; i >= 0; i--)
- fputc ((hi_limb >> (i * BITS_PER_CHAR)) % (1 << BITS_PER_CHAR), stream);
-
- /* Output the remaining limbs. */
- for (s = xsize - 2; s >= 0; s--)
- {
- mp_limb_t x_limb;
+ /* total bytes to be written */
+ ssize = 4 + bytes;
- x_limb = xp[s];
- for (i = BYTES_PER_MP_LIMB - 1; i >= 0; i--)
- fputc ((x_limb >> (i * BITS_PER_CHAR)) % (1 << BITS_PER_CHAR), stream);
- }
- return ferror (stream) ? 0 : ABS (out_bytesize) + 4;
+ /* twos complement negative for the size value */
+ bytes = (xsize >= 0 ? bytes : -bytes);
+
+ /* so we don't rely on sign extension in ">>" */
+ ASSERT_ALWAYS (sizeof (bytes) >= 4);
+
+ bp[-4] = bytes >> 24;
+ bp[-3] = bytes >> 16;
+ bp[-2] = bytes >> 8;
+ bp[-1] = bytes;
+ bp -= 4;
+
+ if (fp == 0)
+ fp = stdout;
+ if (fwrite (bp, ssize, 1, fp) != 1)
+ ssize = 0;
+
+ (*__gmp_free_func) (tp, tsize);
+ return ssize;
}