source: trunk/third/gmp/mpz/inp_raw.c @ 18191

Revision 18191, 6.8 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18190, which included commits to RCS files with non-trunk default branches.
Line 
1/* mpz_inp_raw -- read an mpz_t in raw format.
2
3Copyright 2001, 2002 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 2.1 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20MA 02111-1307, USA. */
21
22#include <stdio.h>
23#include "gmp.h"
24#include "gmp-impl.h"
25
26
27/* NTOH_LIMB_FETCH fetches a limb which is in network byte order (ie. big
28   endian) and produces a normal host byte order result. */
29
30#if HAVE_LIMB_BIG_ENDIAN
31#define NTOH_LIMB_FETCH(limb, src)  do { (limb) = *(src); } while (0)
32#endif
33
34/* The generic implementations below very likely come out as lots of
35   separate byte fetches, so if we know the host is little endian then
36   instead use a single load and a purely arithmetic BSWAP_LIMB.  */
37#if HAVE_LIMB_LITTLE_ENDIAN
38#define NTOH_LIMB_FETCH(limb, src)  BSWAP_LIMB_FETCH (limb, src)
39#endif
40
41#if ! defined (NTOH_LIMB_FETCH)
42#if BITS_PER_MP_LIMB == 8
43#define NTOH_LIMB_FETCH(limb, src)  do { (limb) = *(src); } while (0)
44#endif
45#if BITS_PER_MP_LIMB == 16
46#define NTOH_LIMB_FETCH(limb, src)                              \
47  do {                                                          \
48    const unsigned char  *__p = (const unsigned char *) (src);  \
49    (limb) =                                                    \
50      ( (mp_limb_t) __p[0] << 8)                                \
51      + (mp_limb_t) __p[1];                                     \
52  } while (0)
53#endif
54#if BITS_PER_MP_LIMB == 32
55#define NTOH_LIMB_FETCH(limb, src)                              \
56  do {                                                          \
57    const unsigned char  *__p = (const unsigned char *) (src);  \
58    (limb) =                                                    \
59      (  (mp_limb_t) __p[0] << 24)                              \
60      + ((mp_limb_t) __p[1] << 16)                              \
61      + ((mp_limb_t) __p[2] << 8)                               \
62      +  (mp_limb_t) __p[3];                                    \
63  } while (0)
64#endif
65#if ! defined (NTOH_LIMB_FETCH) && BITS_PER_MP_LIMB == 64
66#define NTOH_LIMB_FETCH(limb, src)                              \
67  do {                                                          \
68    const unsigned char  *__p = (const unsigned char *) (src);  \
69    (limb) =                                                    \
70      (  (mp_limb_t) __p[0] << 56)                              \
71      + ((mp_limb_t) __p[1] << 48)                              \
72      + ((mp_limb_t) __p[2] << 40)                              \
73      + ((mp_limb_t) __p[3] << 32)                              \
74      + ((mp_limb_t) __p[4] << 24)                              \
75      + ((mp_limb_t) __p[5] << 16)                              \
76      + ((mp_limb_t) __p[6] << 8)                               \
77      +  (mp_limb_t) __p[7];                                    \
78  } while (0)
79#endif
80#endif
81
82
83/* Enhancement: The byte swap loop ought to be safe to vectorize on Cray
84   etc, but someone who knows what they're doing needs to check it.  */
85
86size_t
87mpz_inp_raw (mpz_ptr x, FILE *fp)
88{
89  unsigned char  csize_bytes[4];
90  mp_size_t      csize, abs_xsize, i;
91  size_t         abs_csize;
92  char           *cp;
93  mp_ptr         xp, sp, ep;
94  mp_limb_t      slimb, elimb;
95
96  if (fp == 0)
97    fp = stdin;
98
99  /* 4 bytes for size */
100  if (fread (csize_bytes, sizeof (csize_bytes), 1, fp) != 1)
101    return 0;
102
103  csize =
104    (  (mp_size_t) csize_bytes[0] << 24)
105    + ((mp_size_t) csize_bytes[1] << 16)
106    + ((mp_size_t) csize_bytes[2] << 8)
107    + ((mp_size_t) csize_bytes[3]);
108
109  /* Sign extend if necessary.
110     Could write "csize -= ((csize & 0x80000000L) << 1)", but that tickles a
111     bug in gcc 3.0 for powerpc64 on AIX.  */
112  if (sizeof (csize) > 4 && csize & 0x80000000L)
113    csize -= 0x80000000L << 1;
114
115  abs_csize = ABS (csize);
116
117  /* round up to a multiple of limbs */
118  abs_xsize = (abs_csize*8 + GMP_NUMB_BITS-1) / GMP_NUMB_BITS;
119
120  if (abs_xsize != 0)
121    {
122      MPZ_REALLOC (x, abs_xsize);
123      xp = PTR(x);
124
125      /* Get limb boundaries right in the read, for the benefit of the
126         non-nails case.  */
127      xp[0] = 0;
128      cp = (char *) (xp + abs_xsize) - abs_csize;
129      if (fread (cp, abs_csize, 1, fp) != 1)
130        return 0;
131
132      if (GMP_NAIL_BITS == 0)
133        {
134          /* Reverse limbs to least significant first, and byte swap.  If
135             abs_xsize is odd then on the last iteration elimb and slimb are
136             the same.  It doesn't seem extra code to handle that case
137             separately, to save an NTOH.  */
138          sp = xp;
139          ep = xp + abs_xsize-1;
140          for (i = 0; i < (abs_xsize+1)/2; i++)
141            {
142              NTOH_LIMB_FETCH (elimb, ep);
143              NTOH_LIMB_FETCH (slimb, sp);
144              *sp++ = elimb;
145              *ep-- = slimb;
146            }
147        }
148      else
149        {
150          /* It ought to be possible to do the transformation in-place, but
151             for now it's easier to use an extra temporary area.  */
152          mp_limb_t  byte, limb;
153          int        bits;
154          mp_size_t  tpos;
155          mp_ptr     tp;
156          TMP_DECL (marker);
157
158          TMP_MARK (marker);
159          tp = TMP_ALLOC_LIMBS (abs_xsize);
160          limb = 0;
161          bits = 0;
162          tpos = 0;
163          for (i = abs_csize-1; i >= 0; i--)
164            {
165              byte = (unsigned char) cp[i];
166              limb |= (byte << bits);
167              bits += 8;
168              if (bits >= GMP_NUMB_BITS)
169                {
170                  ASSERT (tpos < abs_xsize);
171                  tp[tpos++] = limb & GMP_NUMB_MASK;
172                  bits -= GMP_NUMB_BITS;
173                  ASSERT (bits < 8);
174                  limb = byte >> (8 - bits);
175                }
176            }
177          if (bits != 0)
178            {
179              ASSERT (tpos < abs_xsize);
180              tp[tpos++] = limb;
181            }
182          ASSERT (tpos == abs_xsize);
183
184          MPN_COPY (xp, tp, abs_xsize);
185          TMP_FREE (marker);
186        }
187
188      /* GMP 1.x mpz_out_raw wrote high zero bytes, strip any high zero
189         limbs resulting from this.  Should be a non-zero value here, but
190         for safety don't assume that. */
191      MPN_NORMALIZE (xp, abs_xsize);
192    }
193
194  SIZ(x) = (csize >= 0 ? abs_xsize : -abs_xsize);
195  return abs_csize + 4;
196}
Note: See TracBrowser for help on using the repository browser.