/** Iterate over the contents of the content of a variable, calling callback for each. Contents may be: * numeric -> output * a string -> output each character * array/arraybuffer -> call itself on each element * {data:..., count:...} -> call itself object.count times, on object.data * {callback:...} -> call the given function, call itself on return value */ bool jsvIterateCallback( JsVar *data, jsvIterateCallbackFn callback, void *callbackData ) { bool ok = true; // Handle the data being a single numeric. if (jsvIsNumeric(data)) { callback((int)jsvGetInteger(data), callbackData); } // Handle the data being an object. else if (jsvIsObject(data)) { JsVar *callbackVar = jsvObjectGetChild(data, "callback", 0); if (jsvIsFunction(callbackVar)) { JsVar *result = jspExecuteFunction(callbackVar,0,0,NULL); jsvUnLock(callbackVar); if (result) { bool r = jsvIterateCallback(result, callback, callbackData); jsvUnLock(result); return r; } return true; } jsvUnLock(callbackVar); JsVar *countVar = jsvObjectGetChild(data, "count", 0); JsVar *dataVar = jsvObjectGetChild(data, "data", 0); if (countVar && dataVar && jsvIsNumeric(countVar)) { int n = (int)jsvGetInteger(countVar); while (ok && n-- > 0) { ok = jsvIterateCallback(dataVar, callback, callbackData); } } else { jsExceptionHere(JSET_TYPEERROR, "If specifying an object, it must be of the form {data : ..., count : N} or {callback : fn} - got %j", data); ok = false; } jsvUnLock2(countVar, dataVar); } // Handle the data being a string else if (jsvIsString(data)) { JsvStringIterator it; jsvStringIteratorNew(&it, data, 0); while (jsvStringIteratorHasChar(&it) && ok) { char ch = jsvStringIteratorGetChar(&it); callback(ch, callbackData); jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); } // Handle the data being an array buffer else if (jsvIsArrayBuffer(data)) { JsvArrayBufferIterator it; jsvArrayBufferIteratorNew(&it, data, 0); if (JSV_ARRAYBUFFER_GET_SIZE(it.type) == 1 && !JSV_ARRAYBUFFER_IS_SIGNED(it.type)) { JsvStringIterator *sit = &it.it; // faster for single byte arrays - read using the string iterator. while (jsvStringIteratorHasChar(sit)) { callback((int)(unsigned char)jsvStringIteratorGetChar(sit), callbackData); jsvStringIteratorNextInline(sit); } } else { while (jsvArrayBufferIteratorHasElement(&it)) { callback((int)jsvArrayBufferIteratorGetIntegerValue(&it), callbackData); jsvArrayBufferIteratorNext(&it); } } jsvArrayBufferIteratorFree(&it); } // Handle the data being iterable else if (jsvIsIterable(data)) { JsvIterator it; jsvIteratorNew(&it, data, JSIF_EVERY_ARRAY_ELEMENT); while (jsvIteratorHasElement(&it) && ok) { JsVar *el = jsvIteratorGetValue(&it); ok = jsvIterateCallback(el, callback, callbackData); jsvUnLock(el); jsvIteratorNext(&it); } jsvIteratorFree(&it); } else { jsExceptionHere(JSET_TYPEERROR, "Expecting a number or something iterable, got %t", data); ok = false; } return ok; }
void jsvStringIteratorNext(JsvStringIterator *it) { jsvStringIteratorNextInline(it); }
void jsvStringIteratorSetCharAndNext(JsvStringIterator *it, char c) { if (jsvStringIteratorHasChar(it)) it->ptr[it->charIdx] = c; jsvStringIteratorNextInline(it); }