gawk: Cached values

 
 16.4.10.3 Creating and Using Cached Values
 ..........................................
 
 The routines in this minor node allow you to create and release cached
 values.  Like scalar cookies, in theory, cached values are not
 necessary.  You can create numbers and strings using the functions in
 SeeConstructor Functions.  You can then assign those values to
 variables using 'sym_update()' or 'sym_update_scalar()', as you like.
 
    However, you can understand the point of cached values if you
 remember that _every_ string value's storage _must_ come from
 'gawk_malloc()', 'gawk_calloc()', or 'gawk_realloc()'.  If you have 20
 variables, all of which have the same string value, you must create 20
 identical copies of the string.(1)
 
    It is clearly more efficient, if possible, to create a value once,
 and then tell 'gawk' to reuse the value for multiple variables.  That is
 what the routines in this minor node let you do.  The functions are as
 follows:
 
 'awk_bool_t create_value(awk_value_t *value, awk_value_cookie_t *result);'
      Create a cached string or numeric value from 'value' for efficient
      later assignment.  Only values of type 'AWK_NUMBER', 'AWK_REGEX',
      'AWK_STRNUM', and 'AWK_STRING' are allowed.  Any other type is
      rejected.  'AWK_UNDEFINED' could be allowed, but doing so would
      result in inferior performance.
 
 'awk_bool_t release_value(awk_value_cookie_t vc);'
      Release the memory associated with a value cookie obtained from
      'create_value()'.
 
    You use value cookies in a fashion similar to the way you use scalar
 cookies.  In the extension initialization routine, you create the value
 cookie:
 
      static awk_value_cookie_t answer_cookie;  /* static value cookie */
 
      static void
      my_extension_init()
      {
          awk_value_t value;
          char *long_string;
          size_t long_string_len;
 
          /* code from earlier */
          ...
          /* ... fill in long_string and long_string_len ... */
          make_malloced_string(long_string, long_string_len, & value);
          create_value(& value, & answer_cookie);    /* create cookie */
          ...
      }
 
    Once the value is created, you can use it as the value of any number
 of variables:
 
      static awk_value_t *
      do_magic(int nargs, awk_value_t *result)
      {
          awk_value_t new_value;
 
          ...    /* as earlier */
 
          value.val_type = AWK_VALUE_COOKIE;
          value.value_cookie = answer_cookie;
          sym_update("VAR1", & value);
          sym_update("VAR2", & value);
          ...
          sym_update("VAR100", & value);
          ...
      }
 
 Using value cookies in this way saves considerable storage, as all of
 'VAR1' through 'VAR100' share the same value.
 
    You might be wondering, "Is this sharing problematic?  What happens
 if 'awk' code assigns a new value to 'VAR1'; are all the others changed
 too?"
 
    That's a great question.  The answer is that no, it's not a problem.
 Internally, 'gawk' uses "reference-counted strings".  This means that
 many variables can share the same string value, and 'gawk' keeps track
 of the usage.  When a variable's value changes, 'gawk' simply decrements
 the reference count on the old value and updates the variable to use the
 new value.
 
    Finally, as part of your cleanup action (SeeExit Callback
 Functions) you should release any cached values that you created,
 using 'release_value()'.
 
    ---------- Footnotes ----------
 
    (1) Numeric values are clearly less problematic, requiring only a C
 'double' to store.  But of course, GMP and MPFR values _do_ take up more
 memory.