Exemplo n.º 1
0
MutableSlice StringData::reserve(int cap) {
  assert(!isImmutable() && m_count <= 1 && cap >= 0);
  if (cap + 1 <= capacity()) return mutableSlice();

  switch (mode()) {
    default: assert(false);
    case Mode::Small:
      m_data = (char*) smart_malloc(cap + 1);
      memcpy(m_data, m_small, m_len + 1); // includes \0
      setModeAndCap(Mode::Smart, cap + 1);
      break;
    case Mode::Smart:
      // We only use geometric growth when we're heading to the smart
      // allocator.  This is mostly because it was what was tested as
      // a perf win, but it might make sense to do it for Mode::Malloc
      // as well.  Will be revisited soon.
      cap += cap >> 2;
      m_data = (char*) smart_realloc(m_data, cap + 1);
      setModeAndCap(Mode::Smart, cap + 1);
      break;
    case Mode::Malloc:
      m_data = (char*) realloc(m_data, cap + 1);
      setModeAndCap(Mode::Malloc, cap + 1);
      break;
  }
  return MutableSlice(m_data, cap);
}
Exemplo n.º 2
0
ZendCustomElement::ZendCustomElement(void* data_, unsigned data_size,
                                     DtorFunc destructor)
  : m_destructor(destructor)
{
  m_data = smart_malloc(data_size);
  memcpy(m_data, data_, data_size);
}
Exemplo n.º 3
0
// Convert the typical getopt input characters to the php_getopt struct array
static int parse_opts(const char * opts, int opts_len, opt_struct **result) {
  int count = 0;
  for (int i = 0; i < opts_len; i++) {
    if ((opts[i] >= 48 && opts[i] <= 57) ||
        (opts[i] >= 65 && opts[i] <= 90) ||
        (opts[i] >= 97 && opts[i] <= 122)) {
      count++;
    }
  }

  opt_struct *paras = (opt_struct *)smart_malloc(sizeof(opt_struct) * count);
  memset(paras, 0, sizeof(opt_struct) * count);
  *result = paras;
  while ((*opts >= 48 && *opts <= 57) ||  /* 0 - 9 */
         (*opts >= 65 && *opts <= 90) ||  /* A - Z */
         (*opts >= 97 && *opts <= 122)) { /* a - z */
    paras->opt_char = *opts;
    paras->need_param = (*(++opts) == ':') ? 1 : 0;
    paras->opt_name = NULL;
    if (paras->need_param == 1) {
      opts++;
      if (*opts == ':') {
        paras->need_param++;
        opts++;
      }
    }
    paras++;
  }
  return count;
}
Exemplo n.º 4
0
inline void* MemoryManager::smartRealloc(void* inputPtr, size_t nbytes) {
  FTRACE(1, "smartRealloc: {} to {}\n", inputPtr, nbytes);
  assert(nbytes > 0);

  void* ptr = debug ? static_cast<DebugHeader*>(inputPtr) - 1 : inputPtr;

  auto const n = static_cast<SweepNode*>(ptr) - 1;
  if (LIKELY(n->padbytes <= kMaxSmartSize)) {
    void* newmem = smart_malloc(nbytes);
    auto const copySize = std::min(
      n->padbytes - sizeof(SmallNode) - (debug ? sizeof(DebugHeader) : 0),
      nbytes
    );
    newmem = memcpy(newmem, inputPtr, copySize);
    smart_free(inputPtr);
    return newmem;
  }

  // Ok, it's a big allocation.  Since we don't know how big it is
  // (i.e. how much data we should memcpy), we have no choice but to
  // ask malloc to realloc for us.
  auto const oldNext = n->next;
  auto const oldPrev = n->prev;

  auto const newNode = static_cast<SweepNode*>(
    realloc(n, debugAddExtra(nbytes + sizeof(SweepNode)))
  );

  refreshStatsHelper();
  if (newNode != n) {
    oldNext->prev = oldPrev->next = newNode;
  }
  return debugPostAllocate(newNode + 1, 0, 0);
}
Exemplo n.º 5
0
inline void* MemoryManager::smartRealloc(void* ptr, size_t nbytes) {
  FTRACE(3, "smartRealloc: {} to {}\n", ptr, nbytes);
  assert(nbytes > 0);
  auto const n = static_cast<MallocNode*>(ptr) - 1;
  if (LIKELY(n->small.padbytes <= kMaxSmartSize)) {
    void* newmem = smart_malloc(nbytes);
    auto const copySize = std::min(
      n->small.padbytes - sizeof(SmallNode),
      nbytes
    );
    newmem = memcpy(newmem, ptr, copySize);
    smart_free(ptr);
    return newmem;
  }

  // Ok, it's a big allocation.  Since we don't know how big it is
  // (i.e. how much data we should memcpy), we have no choice but to
  // ask malloc to realloc for us.
  auto const oldNext = n->big.next;
  auto const oldPrev = n->big.prev;

  auto const newNode = static_cast<BigNode*>(
    safe_realloc(n, nbytes + sizeof(BigNode))
  );

  refreshStats();
  if (newNode != &n->big) {
    oldNext->prev = oldPrev->next = newNode;
  }
  return newNode + 1;
}
Exemplo n.º 6
0
void* smart_calloc(size_t count, size_t nbytes) {
  auto& mm = MM();
  auto const totalBytes = std::max<size_t>(count * nbytes, 1);
  if (totalBytes <= kMaxSmartSize) {
    return memset(smart_malloc(totalBytes), 0, totalBytes);
  }
  return mm.smartCallocBig(totalBytes);
}
Exemplo n.º 7
0
char* smart_concat(const char* s1, uint32_t len1, const char* s2, uint32_t len2) {
  uint32_t len = len1 + len2;
  char* s = (char*)smart_malloc(len + 1);
  memcpy(s, s1, len1);
  memcpy(s + len1, s2, len2);
  s[len] = 0;
  return s;
}
Exemplo n.º 8
0
c_AwaitAllWaitHandle* c_AwaitAllWaitHandle::Alloc(int32_t cnt) {
  auto size = sizeof(c_AwaitAllWaitHandle) +
              cnt * sizeof(c_WaitableWaitHandle*);
  auto mem = smart_malloc(size);
  auto const waitHandle = new (mem) c_AwaitAllWaitHandle();
  waitHandle->m_cur = cnt - 1;
  return waitHandle;
}
Exemplo n.º 9
0
void* smart_realloc(void* ptr, size_t nbytes) {
  auto& mm = MM();
  if (!ptr) return smart_malloc(nbytes);
  if (!nbytes) {
    smart_free(ptr);
    return nullptr;
  }
  return mm.smartRealloc(ptr, nbytes);
}
Exemplo n.º 10
0
iter_t list_insert(list *plist, iter_t pwhere, void* pdata){
	++plist->m_size;
	iter_t new_item = smart_malloc(sizeof(list_node));
	new_item->m_pdata = pdata;
	new_item->m_next = pwhere;
	new_item->m_prev = pwhere->m_prev;
	new_item->m_next->m_prev = new_item;
	new_item->m_prev->m_next = new_item;
	return new_item;
}
Exemplo n.º 11
0
void* smart_calloc(size_t count, size_t nbytes) {
  auto& mm = MM();
  auto const totalBytes = std::max<size_t>(count * nbytes, 1);
  if (totalBytes <= kMaxSmartSize) {
    return memset(smart_malloc(totalBytes), 0, totalBytes);
  }
  auto const withExtra = mm.debugAddExtra(totalBytes);
  return mm.debugPostAllocate(
    mm.smartCallocBig(withExtra), 0, 0
  );
}
Exemplo n.º 12
0
void BaseVector::cow() {
  TypedValue* newData =
      (TypedValue*)smart_malloc(m_capacity * sizeof(TypedValue));

  assert(newData);

  for (uint i = 0; i < m_size; i++) {
    cellDup(m_data[i], newData[i]);
  }

  m_data = newData;
  m_frozenCopy.reset();
}
Exemplo n.º 13
0
static String HHVM_FUNCTION(get_current_user) {
  int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
  if (pwbuflen < 1) {
    return "";
  }
  char *pwbuf = (char*)smart_malloc(pwbuflen);
  struct passwd pw;
  struct passwd *retpwptr = NULL;
  if (getpwuid_r(getuid(), &pw, pwbuf, pwbuflen, &retpwptr) != 0) {
    smart_free(pwbuf);
    return "";
  }
  String ret(pw.pw_name, CopyString);
  smart_free(pwbuf);
  return ret;
}
Exemplo n.º 14
0
void VectorArray::alloc(uint size) {
  if (size <= FixedSize) {
    m_capacity = FixedSize;
    m_elems = m_fixed;
    m_allocMode = kInline;
    return;
  }
  uint cap = Util::nextPower2(size);
  m_capacity = cap;
  if (!m_nonsmart) {
    m_elems = (TypedValue*) smart_malloc(cap * sizeof(TypedValue));
    m_allocMode = kSmart;
  } else {
    m_elems = (TypedValue*) malloc(cap * sizeof(TypedValue));
    m_allocMode = kMalloc;
  }
}
Exemplo n.º 15
0
/*
 * Change to smart-malloced string.  Then returns a mutable slice of
 * the usable string buffer (minus space for the null terminator).
 */
MutableSlice StringData::escalate(uint32_t cap) {
  assert(isShared() && !isStatic() && cap >= m_len);

  char *buf = (char*)smart_malloc(cap + 1);
  StringSlice s = slice();
  memcpy(buf, s.ptr, s.len);
  buf[s.len] = 0;

  m_big.shared->decRef();
  delist();

  m_data = buf;
  setModeAndCap(Mode::Smart, cap + 1);
  // clear precomputed hashcode
  m_hash = 0;
  assert(checkSane());
  return MutableSlice(buf, cap);
}
Exemplo n.º 16
0
// make an empty string with cap reserve bytes, plus one more for \0
HOT_FUNC
StringData::StringData(int cap) {
  m_hash = 0;
  m_count = 0;
  if (uint32_t(cap) <= MaxSmallSize) {
    m_len = 0;
    m_data = m_small;
    m_small[0] = 0;
    setSmall();
  } else {
    if (UNLIKELY(uint32_t(cap) > MaxSize)) {
      throw InvalidArgumentException("len > 2^31-2", cap);
    }
    m_len = 0;
    m_data = (char*) smart_malloc(cap + 1);
    m_data[0] = 0;
    setModeAndCap(Mode::Smart, cap + 1);
  }
}
Exemplo n.º 17
0
inline void* MemoryManager::smartRealloc(void* ptr, size_t nbytes) {
  FTRACE(3, "smartRealloc: {} to {}\n", ptr, nbytes);
  assert(nbytes > 0);
  auto const n = static_cast<MallocNode*>(ptr) - 1;
  if (LIKELY(n->small.padbytes <= kMaxSmartSize)) {
    void* newmem = smart_malloc(nbytes);
    auto const copySize = std::min(
      n->small.padbytes - sizeof(SmallNode),
      nbytes
    );
    newmem = memcpy(newmem, ptr, copySize);
    smart_free(ptr);
    return newmem;
  }
  // Ok, it's a big allocation.
  auto block = m_heap.resizeBig(ptr, nbytes);
  refreshStats();
  return block.ptr;
}
Exemplo n.º 18
0
String StringUtil::Implode(const Variant& items, const String& delim) {
  if (!isContainer(items)) {
    throw_param_is_not_container();
  }
  int size = getContainerSize(items);
  if (size == 0) return "";

  String* sitems = (String*)smart_malloc(size * sizeof(String));
  int len = 0;
  int lenDelim = delim.size();
  int i = 0;
  for (ArrayIter iter(items); iter; ++iter) {
    new (&sitems[i]) String(iter.second().toString());
    len += sitems[i].size() + lenDelim;
    i++;
  }
  len -= lenDelim; // always one delimiter less than count of items
  assert(i == size);

  String s = String(len, ReserveString);
  char *buffer = s.bufferSlice().ptr;
  const char *sdelim = delim.data();
  char *p = buffer;
  for (int i = 0; i < size; i++) {
    String &item = sitems[i];
    if (i && lenDelim) {
      memcpy(p, sdelim, lenDelim);
      p += lenDelim;
    }
    int lenItem = item.size();
    if (lenItem) {
      memcpy(p, item.data(), lenItem);
      p += lenItem;
    }
    sitems[i].~String();
  }
  smart_free(sitems);
  assert(p - buffer == len);
  s.setSize(len);
  return s;
}
Exemplo n.º 19
0
void StringBuffer::printf(const char *format, ...) {
  va_list ap;
  va_start(ap, format);

  bool printed = false;
  for (int len = 1024; !printed; len <<= 1) {
    va_list v;
    va_copy(v, ap);

    char *buf = (char*)smart_malloc(len);
    if (vsnprintf(buf, len, format, v) < len) {
      append(buf);
      printed = true;
    }
    smart_free(buf);

    va_end(v);
  }

  va_end(ap);
}
Exemplo n.º 20
0
void VectorArray::grow(uint newSize) {
  assert(newSize > FixedSize);
  m_capacity = Util::nextPower2(newSize);
  if (!m_nonsmart) {
    assert(m_allocMode == kInline || m_allocMode == kSmart);
    if (m_allocMode == kInline) {
      m_elems = (TypedValue*)smart_malloc(m_capacity * sizeof(TypedValue));
      memcpy(m_elems, m_fixed, m_size * sizeof(TypedValue));
      m_allocMode = kSmart;
    } else {
      m_elems = (TypedValue*)smart_realloc(m_elems,
                                           m_capacity * sizeof(TypedValue));
    }
  } else if (m_allocMode == kInline) {
    m_elems = (TypedValue*)malloc(m_capacity * sizeof(TypedValue));
    memcpy(m_elems, m_fixed, m_size * sizeof(TypedValue));
    m_allocMode = kMalloc;
  } else {
    assert(m_allocMode == kMalloc);
    m_elems = (TypedValue*)realloc(m_elems, m_capacity * sizeof(TypedValue));
  }
}
Exemplo n.º 21
0
HOT_FUNC
void StringData::initCopy(const char* data, int len) {
  if (uint32_t(len) > MaxSize) {
    throw InvalidArgumentException("len > 2^31-2", len);
  }
  m_hash = 0;
  m_count = 0;
  if (uint32_t(len) <= MaxSmallSize) {
    memcpy(m_small, data, len);
    m_len = len;
    m_data = m_small;
    m_small[len] = 0;
    setSmall();
  } else {
    char *buf = (char*)smart_malloc(len + 1);
    memcpy(buf, data, len);
    buf[len] = 0;
    m_len = len;
    m_cdata = buf;
    setModeAndCap(Mode::Smart, len + 1);
  }
  assert(checkSane());
}
Exemplo n.º 22
0
static Variant HHVM_FUNCTION(gmp_strval,
                            const Variant& data,
                            const int64_t base /* = 10 */) {
  mpz_t gmpData;

  if (base < GMP_MIN_BASE || (base > -2 && base < 2) || base > GMP_MAX_BASE) {
    raise_warning(cs_GMP_INVALID_BASE_VALUE,
                  cs_GMP_FUNC_NAME_GMP_STRVAL,
                  base,
                  GMP_MAX_BASE);
    return false;
  }

  if (!variantToGMPData(cs_GMP_FUNC_NAME_GMP_STRVAL, gmpData, data, base)) {
    return false;
  }

  int charLength = mpz_sizeinbase(gmpData, abs(base)) + 1;
  if (mpz_sgn(gmpData) < 0) {
    ++charLength;
  }

  char *charStr = (char*) smart_malloc(charLength);
  if (!mpz_get_str(charStr, base, gmpData)) {
    smart_free(charStr);
    mpz_clear(gmpData);

    return false;
  }

  String returnValue(charStr);

  smart_free(charStr);
  mpz_clear(gmpData);

  return returnValue;
}
Exemplo n.º 23
0
static Array HHVM_FUNCTION(getopt, const String& options,
                                   const Variant& longopts /*=null */) {
  opt_struct *opts, *orig_opts;
  int len = parse_opts(options.data(), options.size(), &opts);

  if (!longopts.isNull()) {
    Array arropts = longopts.toArray();
    int count = arropts.size();

    /* the first <len> slots are filled by the one short ops
     * we now extend our array and jump to the new added structs */
    opts = (opt_struct *)smart_realloc(
      opts, sizeof(opt_struct) * (len + count + 1));
    orig_opts = opts;
    opts += len;

    memset(opts, 0, count * sizeof(opt_struct));

    for (ArrayIter iter(arropts); iter; ++iter) {
      String entry = iter.second().toString();

      opts->need_param = 0;
      opts->opt_name = strdup(entry.data());
      len = strlen(opts->opt_name);
      if ((len > 0) && (opts->opt_name[len - 1] == ':')) {
        opts->need_param++;
        opts->opt_name[len - 1] = '\0';
        if ((len > 1) && (opts->opt_name[len - 2] == ':')) {
          opts->need_param++;
          opts->opt_name[len - 2] = '\0';
        }
      }
      opts->opt_char = 0;
      opts++;
    }
  } else {
    opts = (opt_struct*) smart_realloc(opts, sizeof(opt_struct) * (len + 1));
    orig_opts = opts;
    opts += len;
  }

  /* php_getopt want to identify the last param */
  opts->opt_char   = '-';
  opts->need_param = 0;
  opts->opt_name   = NULL;

  static const StaticString s_argv("argv");
  Array vargv = php_global(s_argv).toArray();
  int argc = vargv.size();
  char **argv = (char **)smart_malloc((argc+1) * sizeof(char*));
  std::vector<String> holders;
  int index = 0;
  for (ArrayIter iter(vargv); iter; ++iter) {
    String arg = iter.second().toString();
    holders.push_back(arg);
    argv[index++] = (char*)arg.data();
  }
  argv[index] = NULL;

  /* after our pointer arithmetic jump back to the first element */
  opts = orig_opts;

  int o;
  char *php_optarg = NULL;
  int php_optind = 1;

  SCOPE_EXIT {
    free_longopts(orig_opts);
    smart_free(orig_opts);
    smart_free(argv);
  };

  Array ret = Array::Create();

  Variant val;
  int optchr = 0;
  int dash = 0; /* have already seen the - */
  char opt[2] = { '\0' };
  char *optname;
  int optname_len = 0;
  int php_optidx;
  while ((o = php_getopt(argc, argv, opts, &php_optarg, &php_optind, 0, 1,
                         optchr, dash, php_optidx))
         != -1) {
    /* Skip unknown arguments. */
    if (o == '?') {
      continue;
    }

    /* Prepare the option character and the argument string. */
    if (o == 0) {
      optname = opts[php_optidx].opt_name;
    } else {
      if (o == 1) {
        o = '-';
      }
      opt[0] = o;
      optname = opt;
    }

    if (php_optarg != NULL) {
      /* keep the arg as binary, since the encoding is not known */
      val = String(php_optarg, CopyString);
    } else {
      val = false;
    }

    /* Add this option / argument pair to the result hash. */
    optname_len = strlen(optname);
    if (!(optname_len > 1 && optname[0] == '0') &&
        is_numeric_string(optname, optname_len, NULL, NULL, 0) ==
        KindOfInt64) {
      /* numeric string */
      int optname_int = atoi(optname);
      if (ret.exists(optname_int)) {
        Variant &e = ret.lvalAt(optname_int);
        if (!e.isArray()) {
          ret.set(optname_int, make_packed_array(e, val));
        } else {
          e.toArrRef().append(val);
        }
      } else {
        ret.set(optname_int, val);
      }
    } else {
      /* other strings */
      String key(optname, strlen(optname), CopyString);
      if (ret.exists(key)) {
        Variant &e = ret.lvalAt(key);
        if (!e.isArray()) {
          ret.set(key, make_packed_array(e, val));
        } else {
          e.toArrRef().append(val);
        }
      } else {
        ret.set(key, val);
      }
    }

    php_optarg = NULL;
  }

  return ret;
}
Exemplo n.º 24
0
static bool HHVM_METHOD(Collator, sortWithSortKeys, VRefParam arr) {
  FETCH_COL(data, this_, false);
  data->clearError();

  if (!arr.isArray()) {
    return true;
  }

  Array hash = arr.toArray();
  if (hash.size() == 0) {
    return true;
  }

  // Preallocate sort keys buffer
  size_t sortKeysOffset = 0;
  size_t sortKeysLength = DEF_SORT_KEYS_BUF_SIZE;
  char*  sortKeys = (char*)smart_malloc(sortKeysLength);
  if (!sortKeys) {
    throw Exception("Out of memory");
  }
  SCOPE_EXIT{ smart_free(sortKeys); };

  // Preallocate index buffer
  size_t sortIndexPos = 0;
  size_t sortIndexLength = DEF_SORT_KEYS_INDX_BUF_SIZE;
  auto   sortIndex = (collator_sort_key_index_t*)smart_malloc(
                  sortIndexLength * sizeof(collator_sort_key_index_t));
  if (!sortIndex) {
    throw Exception("Out of memory");
  }
  SCOPE_EXIT{ smart_free(sortIndex); };

  // Translate input hash to sortable index
  auto pos_limit = hash->iter_end();
  for (ssize_t pos = hash->iter_begin(); pos != pos_limit;
       pos = hash->iter_advance(pos)) {
    Variant val(hash->getValue(pos));

    // Convert to UTF16
    icu::UnicodeString strval;
    if (val.isString()) {
      UErrorCode error = U_ZERO_ERROR;
      strval = u16(val.toString(), error);
      if (U_FAILURE(error)) {
        return false;
      }
     }

    // Generate sort key
    int sortkey_len =
      ucol_getSortKey(data->collator(),
                      strval.getBuffer(), strval.length(),
                      (uint8_t*)(sortKeys + sortKeysOffset),
                      sortKeysLength - sortKeysOffset);

    // Check for key buffer overflow
    if (sortkey_len > (sortKeysLength - sortKeysOffset)) {
      int32_t inc = (sortkey_len > DEF_SORT_KEYS_BUF_INCREMENT)
                  ?  sortkey_len : DEF_SORT_KEYS_BUF_INCREMENT;
      sortKeysLength += inc;
      sortKeys = (char*)smart_realloc(sortKeys, sortKeysLength);
      if (!sortKeys) {
        throw Exception("Out of memory");
      }
      sortkey_len =
        ucol_getSortKey(data->collator(),
                        strval.getBuffer(), strval.length(),
                        (uint8_t*)(sortKeys + sortKeysOffset),
                        sortKeysLength - sortKeysOffset);
      assert(sortkey_len <= (sortKeysLength - sortKeysOffset));
    }

    // Check for index buffer overflow
    if ((sortIndexPos + 1) > sortIndexLength) {
      sortIndexLength += DEF_SORT_KEYS_INDX_BUF_INCREMENT;
      sortIndex = (collator_sort_key_index_t*)smart_realloc(sortIndex,
                      sortIndexLength * sizeof(collator_sort_key_index_t));
      if (!sortIndex) {
        throw Exception("Out of memory");
      }
    }

    // Initially store offset into buffer, update later to deal with reallocs
    sortIndex[sortIndexPos].key = (char*)sortKeysOffset;
    sortKeysOffset += sortkey_len;

    sortIndex[sortIndexPos].valPos = pos;
    ++sortIndexPos;
  }

  // Update keys to location in realloc'd buffer
  for (int i = 0; i < sortIndexPos; ++i) {
    sortIndex[i].key = sortKeys + (ptrdiff_t)sortIndex[i].key;
  }

  zend_qsort(sortIndex, sortIndexPos,
             sizeof(collator_sort_key_index_t),
             collator_cmp_sort_keys, nullptr);

  Array ret = Array::Create();
  for (int i = 0; i < sortIndexPos; ++i) {
    ret.append(hash->getValue(sortIndex[i].valPos));
  }
  arr = ret;
  return true;
}
Exemplo n.º 25
0
static void *php_xml_malloc_wrapper(size_t sz) {
  return smart_malloc(sz);
}
Exemplo n.º 26
0
static double collator_u_strtod(const UChar *nptr, UChar **endptr) {
  const UChar *u = nptr, *nstart;
  UChar c = *u;
  int any = 0;

  while (u_isspace(c)) {
    c = *++u;
  }
  nstart = u;

  if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
    c = *++u;
  }

  while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
    any = 1;
    c = *++u;
  }

  if (c == 0x2E /*'.'*/) {
    c = *++u;
    while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
      any = 1;
      c = *++u;
    }
  }

  if ((c == 0x65 /*'e'*/ || c == 0x45 /*'E'*/) && any) {
    const UChar *e = u;
    int any_exp = 0;

    c = *++u;
    if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
      c = *++u;
    }

    while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
      any_exp = 1;
      c = *++u;
    }

    if (!any_exp) {
      u = e;
    }
  }

  if (any) {
    char buf[64], *numbuf, *bufpos;
    int length = u - nstart;
    double value;

    if (length < (int)sizeof(buf)) {
      numbuf = buf;
    } else {
      numbuf = (char *) smart_malloc(length + 1);
    }

    bufpos = numbuf;

    while (nstart < u) {
      *bufpos++ = (char) *nstart++;
    }

    *bufpos = '\0';
    value = zend_strtod(numbuf, nullptr);

    if (numbuf != buf) {
      smart_free(numbuf);
    }

    if (endptr != nullptr) {
      *endptr = (UChar *)u;
    }

    return value;
  }

  if (endptr != nullptr) {
    *endptr = (UChar *)nptr;
  }

  return 0;
}