In src/Quad_RVAL.cc <http://quad_rval.cc/> and the GNU APL info doc, it's 
stated that the ⎕RVAL operator requires glibc. This is stated to be required 
due to the use of the glibc functions random_r(),  which would also imply the 
use of initstate_r() and setstate_r() to initialize and set the state. 

However, looking at the source, there is no use of these glibc functions. The 
code uses random(), initstate(), and setstate() -- which are available on 
platforms that use libraries other than glibc (for example macOS).

//----------------------------------------------------------------------------
Quad_RVAL::Quad_RVAL()
   : QuadFunction(TOK_Quad_RVAL)
{
enum { count = sizeof(subfunction_infos) / sizeof(*subfunction_infos) };
   init_function_group(subfunction_infos, count, "⎕RVAL");

   N = 8;
   desired_maxdepth = 4;
   memset(state, 0, sizeof(state));
   initstate(1, state, N);                    // <<< uses initstate() instead 
of initstate_r()

   while (desired_shape.get_rank() < MAX_RANK)
         desired_shape.add_shape_item(1);

   desired_ranks.push_back(0);

   desired_types.push_back(0);   // no chars
   desired_types.push_back(1);   // ints
   desired_types.push_back(0);   // no real
   desired_types.push_back(0);   // no complex
   desired_types.push_back(0);   // no nested
}
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
Value_P
Quad_RVAL::generator_state(const Value & B)
{
   // expect an empty, 8, 16, 32, 64, 128, or 256 byte integer vector
   //
   if (B.get_rank() != 1)   RANK_ERROR;

const ShapeItem new_N = B.element_count();
   if (new_N !=   0 && new_N !=   8 && new_N !=  32 &&
       new_N !=  64 && new_N != 128 && new_N != 256)
      {
        MORE_ERROR() << "bad new_N (aka. ⍴B) in generator_state()";
        LENGTH_ERROR;
      }

   // always return the previous state
   //
Value_P Z(N, LOC);
   loop(n, N)   Z->next_ravel_Int(state[n] & 0xFF);
   Z->check_value(LOC);

   if (new_N)   // set generator state
      {
        // make sure that all values are bytes
        //
        loop(b, N)
            {
              const APL_Integer byte = B.get_cravel(b).get_int_value();
              if ((byte < -256) || (byte >  255))
                 {
                   MORE_ERROR() << "Bad right argument B in 0 ⎕RVAL B,"
                                   "expecting bytes (integers -256...255)";
                   DOMAIN_ERROR;
                 }
            }
        N = new_N;
        loop(b, N)
            {
               state[b] = B.get_cravel(b).get_int_value();
            }
         setstate(state);     // uses setstate() instead of setstate_r()
      }

   return Z;
}
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
uint64_t
Quad_RVAL::rand17()
{
const int32_t rnd = random();     // uses random() instead of random_r()

   // the lower bits are less random, so we xor the upper 16 bits into
   // the lower 16 bits and return them.
   return (rnd ^ (rnd >> 16)) & 0x1FFFF;
}
//----------------------------------------------------------------------------

I have tested a build of GNU APL SVN 1922 and "reversed" the test for the 
HAVE_LIBC in Quadf_RVAL.cc <http://quadf_rval.cc/> so that the code would try 
to be compiled under macOS. Everything related to ⎕RVAL seems to work in my 
limited testing (it at least didn't crash the interpreter).

Is the use of random() instead of random_r(), etc. in the code an oversight. Or 
is the documentation incorrect?

- Paul Rockwell


  • Question re: ⎕... Paul Rockwell

Reply via email to