*/ REBSER *Temp_Bin_Str_Managed(REBVAL *val, REBCNT *index, REBCNT *length) /* ** Determines if UTF8 conversion is needed for a series before it ** is used with a byte-oriented function. ** ** If conversion is needed, a UTF8 series will be created. Otherwise, ** the source series is returned as-is. ** ** Note: This routine should only be used to generate a value used ** for temporary purposes, because it has a "surprising variance" ** regarding its input. If the value's series can be reused, it is-- ** and this depends on an implementation detail of internal encoding ** that the user should not be aware of (they need not know if the ** internal representation of an ASCII string uses 1, 2, or however ** many bytes). But copying vs. non-copying means the resulting ** data might or might not have previous values available to step ** back into from the originating series! ** ** !!! Should performance dictate it, the callsites could be ** adapted to know whether this produced a new series or not, and ** instead of managing a created result they could be responsible ** for freeing it if so. ** ***********************************************************************/ { REBCNT len = (length && *length) ? *length : VAL_LEN(val); REBSER *series; assert(IS_BINARY(val) || ANY_STR(val)); if (len == 0 || IS_BINARY(val) || VAL_STR_IS_ASCII(val)) { // If it's zero length, BINARY!, or an ANY-STRING! whose bytes are // all values less than 128, we reuse the series. series = VAL_SERIES(val); ASSERT_SERIES_MANAGED(series); if (index) *index = VAL_INDEX(val); if (length) *length = len; } else { // UTF-8 conversion is required, and we manage the result. series = Make_UTF8_From_Any_String(val, len, OPT_ENC_CRLF_MAYBE); MANAGE_SERIES(series); if (index) *index = 0; if (length) *length = SERIES_TAIL(series); } return series; }
// // Temp_Bin_Str_Managed: C // // Determines if UTF8 conversion is needed for a series before it // is used with a byte-oriented function. // // If conversion is needed, a UTF8 series will be created. Otherwise, // the source series is returned as-is. // // Note: This routine should only be used to generate a value used // for temporary purposes, because it has a "surprising variance" // regarding its input. If the value's series can be reused, it is-- // and this depends on an implementation detail of internal encoding // that the user should not be aware of (they need not know if the // internal representation of an ASCII string uses 1, 2, or however // many bytes). But copying vs. non-copying means the resulting // data might or might not have previous values available to step // back into from the originating series! // // !!! Should performance dictate it, the callsites could be // adapted to know whether this produced a new series or not, and // instead of managing a created result they could be responsible // for freeing it if so. // REBSER *Temp_Bin_Str_Managed(const REBVAL *val, REBCNT *index, REBCNT *length) { REBCNT len = (length && *length) ? *length : VAL_LEN_AT(val); REBSER *series; assert(IS_BINARY(val) || ANY_STRING(val)); // !!! This used to check `len == 0` and reuse a zero length string. // However, the zero length string could have the wrong width. We are // expected to be returning a BYTE_SIZE() string, and that confused // things. It's not a good idea to mutate the source string (e.g. // reallocate under a new width) so consider having an EMPTY_BYTE_STRING // like EMPTY_ARRAY which is protected to hand back. // if ( IS_BINARY(val) || ( VAL_BYTE_SIZE(val) && All_Bytes_ASCII(VAL_BIN_AT(val), VAL_LEN_AT(val)) ) ){ // // It's BINARY!, or an ANY-STRING! whose codepoints are all values in // ASCII (0x00 => 0x7F), hence not needing any UTF-8 encoding. // series = VAL_SERIES(val); ASSERT_SERIES_MANAGED(series); if (index) *index = VAL_INDEX(val); if (length) *length = len; } else { // UTF-8 conversion is required, and we manage the result. series = Make_UTF8_From_Any_String(val, len, OPT_ENC_CRLF_MAYBE); MANAGE_SERIES(series); #if !defined(NDEBUG) // // Also, PROTECT the result in the debug build...because since the // caller doesn't know if a new series was created or if the initial // data is being used, they should not be modifying it! (We don't // want to protect the original data, because we wouldn't know when // we were allowed to unlock it...there's no later call in this // model to clean up the series.) { REBVAL protect; Val_Init_String(&protect, series); Protect_Value(&protect, FLAGIT(PROT_SET)); // just a string...not /DEEP...shouldn't need to Unmark() } #endif if (index) *index = 0; if (length) *length = SER_LEN(series); } assert(BYTE_SIZE(series)); return series; }
*/ REBSER *Make_Object(REBSER *parent, REBVAL value[]) /* ** Create an object from a parent object and a spec block. ** The words within the resultant object are not bound. ** ***********************************************************************/ { REBSER *words; REBSER *object; PG_Reb_Stats->Objects++; if (!value || IS_END(value)) { if (parent) { object = Copy_Array_Core_Managed( parent, 0, SERIES_TAIL(parent), TRUE, TS_CLONE ); } else { object = Make_Frame(0, TRUE); MANAGE_FRAME(object); } } else { words = Collect_Frame(parent, &value[0], BIND_ONLY); // GC safe object = Create_Frame(words, 0); // GC safe if (parent) { if (Reb_Opts->watch_obj_copy) Debug_Fmt(cs_cast(BOOT_STR(RS_WATCH, 2)), SERIES_TAIL(parent) - 1, FRM_WORD_SERIES(object)); // Bitwise copy parent values (will have bits fixed by Clonify) memcpy( FRM_VALUES(object) + 1, FRM_VALUES(parent) + 1, (SERIES_TAIL(parent) - 1) * sizeof(REBVAL) ); // For values we copied that were blocks and strings, replace // their series components with deep copies of themselves: Clonify_Values_Len_Managed( BLK_SKIP(object, 1), SERIES_TAIL(object) - 1, TRUE, TS_CLONE ); // The *word series* might have been reused from the parent, // based on whether any words were added, or we could have gotten // a fresh one back. Force our invariant here (as the screws // tighten...) ENSURE_SERIES_MANAGED(FRM_WORD_SERIES(object)); MANAGE_SERIES(object); } else { MANAGE_FRAME(object); } assert(words == FRM_WORD_SERIES(object)); } ASSERT_SERIES_MANAGED(object); ASSERT_SERIES_MANAGED(FRM_WORD_SERIES(object)); ASSERT_FRAME(object); return object; }