Branch: Tag:

2011-03-19

2011-03-19 00:14:33 by Martin Stjernholm <mast@lysator.liu.se>

Instantiate the fallback codecs instead of using the master directly.

(encode|decode)_value now instantiates a local codec instance from
master()->Encoder or master()->Decoder, respectively. That to make it
possible to keep local state. Specifically, it fixes the problem that the
reverse lookup mappings in the encoder get populated way too early when the
master is used directly.

The codecs are only instantiated on-demand, though.

122:   #define ID_ENTRY_INHERIT 3   #define ID_ENTRY_ALIAS 4    + static struct object *lookup_codec (struct pike_string *codec_name) + { +  struct object *m = get_master(); +  if (!m) { +  /* Use a dummy if there's no master around yet. This will cause an +  * error in apply later, so we don't need to bother. */ +  return clone_object (null_program, 0); +  } +  else { +  ref_push_object (m); +  ref_push_string (codec_name); +  o_index(); +  if (UNSAFE_IS_ZERO (Pike_sp - 1)) { +  add_ref (m); +  return m; +  } +  else { +  apply_svalue (Pike_sp - 1, 0); +  if (Pike_sp[-1].type != T_OBJECT) +  Pike_error ("master()->%s() did not return an object. Got: %O\n", +  codec_name->str, Pike_sp - 1); +  m = (--Pike_sp)->u.object; +  pop_stack(); +  return m; +  } +  } + } +    struct encode_data   {    int canonic;
138:   #endif   };    + static struct object *encoder_codec (struct encode_data *data) + { +  struct pike_string *encoder_str; +  if (data->codec) return data->codec; +  MAKE_CONST_STRING (encoder_str, "Encoder"); +  return data->codec = lookup_codec (encoder_str); + } +    /* Convert to/from forward reference ID. */   #define CONVERT_ENTRY_ID(ID) (-((ID) - COUNTER_START) - (-COUNTER_START + 1))   
870:    if (data->canonic)    Pike_error("Canonical encoding of objects not supported.\n");    push_svalue(val); -  apply(data->codec, "nameof", 1); +  apply(encoder_codec (data), "nameof", 1);    EDB(5, fprintf(stderr, "%*s->nameof: ", data->depth, "");    print_svalue(stderr, Pike_sp-1);    fputc('\n', stderr););
926:    */    data->buf.s.str[to_change] = 99;    -  fun = find_identifier("encode_object", data->codec->prog); +  fun = find_identifier("encode_object", +  encoder_codec (data)->prog);    if (fun < 0)    Pike_error("Cannot encode objects without an "    "\"encode_object\" function in the codec.\n");
953:    Pike_error("Canonical encoding of functions not supported.\n");    check_stack(1);    push_svalue(val); -  apply(data->codec,"nameof", 1); +  apply(encoder_codec (data),"nameof", 1);    if(Pike_sp[-1].type == T_INT && Pike_sp[-1].subtype==NUMBER_UNDEFINED)    {    if(val->subtype != FUNCTION_BUILTIN)
1010:    Pike_error("Encoding of unfixated programs not supported.\n");    check_stack(1);    push_svalue(val); -  apply(data->codec,"nameof", 1); +  apply(encoder_codec (data),"nameof", 1);    if(Pike_sp[-1].type == val->type)    Pike_error("Error in master()->nameof(), same type returned.\n");    if(Pike_sp[-1].type == T_INT && Pike_sp[-1].subtype == NUMBER_UNDEFINED)
1840:   static void free_encode_data(struct encode_data *data)   {    toss_buffer(& data->buf); +  if (data->codec) free_object (data->codec);    free_mapping(data->encoded);    free_array(data->delayed);   }
1856:    *! Almost any value can be coded, mappings, floats, arrays, circular    *! structures etc.    *! -  *! If @[codec] is specified, it's used as the codec for the decode. -  *! If no codec is specified, the current master object will be used. +  *! If @[codec] is specified, it's used as the codec for the encode. +  *! If none is specified, then one is instantiated through +  *! @expr{master()->Encoder()@}. As a compatibility fallback, the +  *! master itself is used if it has no @expr{Encoder@} class.    *!    *! If @expr{@[codec]->nameof(o)@} returns @tt{UNDEFINED@} for an    *! object, @expr{val = o->encode_object(o)@} will be called. The
1919:    }    data->codec=Pike_sp[1-args].u.object;    }else{ -  data->codec=get_master(); -  if (!data->codec) { -  /* Use a dummy if there's no master around yet, to avoid checks. */ -  push_object (clone_object (null_program, 0)); -  args++; -  data->codec = Pike_sp[-1].u.object; +  data->codec=NULL;    } -  } +        SET_ONERROR(tmp, free_encode_data, data);    addstr("\266ke0", 4);
1938:       UNSET_ONERROR(tmp);    +  if (data->codec) free_object (data->codec);    free_mapping(data->encoded);    free_array (data->delayed);   
2003:    }    data->codec=Pike_sp[1-args].u.object;    }else{ -  data->codec=get_master(); -  if (!data->codec) { -  /* Use a dummy if there's no master around yet, to avoid checks. */ -  push_object (clone_object (null_program, 0)); -  args++; -  data->codec = Pike_sp[-1].u.object; +  data->codec=NULL;    } -  } +        SET_ONERROR(tmp, free_encode_data, data);    addstr("\266ke0", 4);
2022:       UNSET_ONERROR(tmp);    +  if (data->codec) free_object (data->codec);    free_mapping(data->encoded);    free_array (data->delayed);   
2055:    struct unfinished_obj_link *unfinished_placeholders;    struct svalue counter;    struct object *codec; +  int explicit_codec;    int pickyness;    int pass;    int delay_counter;
2074:   #endif   };    + static struct object *decoder_codec (struct decode_data *data) + { +  struct pike_string *decoder_str; +  if (data->codec) return data->codec; +  MAKE_CONST_STRING (decoder_str, "Decoder"); +  return data->codec = lookup_codec (decoder_str); + } +    static void decode_value2(struct decode_data *data);      static int my_extract_char(struct decode_data *data)
2883:    switch(num)    {    case 0: -  apply(data->codec,"objectof", 1); +  apply(decoder_codec (data),"objectof", 1);    break;       case 1:
2951:       ref_push_object(o);    decode_value2(data); -  if(!data->codec) -  decode_error(data, Pike_sp - 1, -  "Cannot decode object without codec.\n"); +     -  fun = find_identifier("decode_object", data->codec->prog); +  fun = find_identifier("decode_object", decoder_codec (data)->prog);    if (fun < 0)    decode_error(data, Pike_sp - 1,    "Cannot decode objects without a "
3049:    switch(num)    {    case 0: -  apply(data->codec,"functionof", 1); +  apply(decoder_codec (data),"functionof", 1);    break;       case 1: {
3126:    struct program *p;       decode_value2(data); -  apply(data->codec,"programof", 1); +  apply(decoder_codec (data),"programof", 1);       p = program_from_svalue(Pike_sp-1);   
3181:       debug_malloc_touch(p);    ref_push_program(p); -  apply(data->codec, "__register_new_program", 1); +  apply(decoder_codec (data), "__register_new_program", 1);       /* return a placeholder */    if(Pike_sp[-1].type == T_OBJECT)
3694:    int decode_fun = -1;    struct unfinished_obj_link *l, **ptr;    if (data->unfinished_objects) { -  if(!data->codec) -  decode_error(data, Pike_sp - 1, -  "Cannot decode object without codec.\n"); -  -  decode_fun = -  find_identifier("decode_object", data->codec->prog); +  decode_fun = find_identifier("decode_object", +  decoder_codec (data)->prog);    if (decode_fun < 0)    decode_error(data, Pike_sp - 1,    "Cannot decode objects without a "
3731:    free((char *)l);       /* Let the codec do it's job... */ -  apply_low(data->codec, decode_fun, 2); +  apply_low(decoder_codec (data), decode_fun, 2);    if ((Pike_sp[-1].type == T_ARRAY) &&    ((fun = FIND_LFUN(o->prog, LFUN_CREATE)) != -1)) {    /* Call lfun::create(@args). */
3814: Inside #if 0
   /* Is this necessary? In that case, how do we pass an    * adequate context to __register_new_program so that it    * knows which program is being decoded? */ -  if (data->codec) { +     ref_push_program (p); -  apply (data->codec, "__register_new_program", 1); +  apply (decoder_codec (data), "__register_new_program", 1);       /* Returns a placeholder. */    if (Pike_sp[-1].type == T_OBJECT) {
3829: Inside #if 0
   decode_error (data, NULL, "Expected placeholder object or zero "    "from __register_new_program.\n");    pop_stack(); -  } +    #endif       break;
3931:       {    int fun = find_identifier("__register_new_program", -  data->codec->prog); +  decoder_codec (data)->prog);       if (fun >= 0) {    ref_push_program(p);
4879:   #endif       free_string (data->data_str); -  free_object (data->codec); +  if (data->codec) free_object (data->codec);    free_mapping(data->decoded);       while(data->unfinished_programs)
4979:       /* Attempt to avoid infinite recursion on circular structures. */    for (data = current_decode; data; data=data->next) { -  if (data->raw == tmp && data->codec == codec +  if (data->raw == tmp && +  (codec ? data->codec == codec : !data->explicit_codec)   #ifdef PIKE_THREADS    && data->thread_state == Pike_interpreter.thread_state   #endif
5005:    data->len=tmp->len;    data->ptr=0;    data->codec=codec; +  data->explicit_codec = codec ? 1 : 0;    data->pickyness=0;    data->pass=1;    data->unfinished_programs=0;
5036:    data->decoded=allocate_mapping(128);       add_ref (data->data_str); -  add_ref (data->codec); +  if (data->codec) add_ref (data->codec);   #ifdef PIKE_THREADS    add_ref (data->thread_obj);   #endif
5328:    *! coded.    *!    *! If @[codec] is specified, it's used as the codec for the decode. -  *! If no codec is specified, the current master object will be used. +  *! If none is specified, then one is instantiated through +  *! @expr{master()->Decoder()@}. As a compatibility fallback, the +  *! master itself is used if it has no @expr{Decoder@} class.    *!    *! @seealso    *! @[encode_value()], @[encode_value_canonic()]
5376:    }    /* Fall through. */    case 1: -  codec = get_master(); -  if (!codec) { +  if (!get_master()) {    /* The codec used for decoding the master program. */    push_object (clone_object (MasterCodec_program, 0));    args++;    codec = Pike_sp[-1].u.object;    } -  +  else +  codec = NULL;    }       if(!my_decode(s, codec