/*! * Copyright (c) 2019 by Contributors * \file common.cc * \brief This file provide basic facilities for string * to make programming convenient. */ #include "common.h" #include #include using std::string; namespace dgl { namespace network { // In most cases, delim contains only one character. In this case, we // use CalculateReserveForVector to count the number of elements should // be reserved in result vector, and thus optimize SplitStringUsing. static int CalculateReserveForVector(const std::string& full, const char* delim) { int count = 0; if (delim[0] != '\0' && delim[1] == '\0') { // Optimize the common case where delim is a single character. char c = delim[0]; const char* p = full.data(); const char* end = p + full.size(); while (p != end) { if (*p == c) { // This could be optimized with hasless(v,1) trick. ++p; } else { while (++p != end && *p != c) { // Skip to the next occurence of the delimiter. } ++count; } } } return count; } void SplitStringUsing(const std::string& full, const char* delim, std::vector* result) { CHECK(delim != NULL); CHECK(result != NULL); result->reserve(CalculateReserveForVector(full, delim)); back_insert_iterator< std::vector > it(*result); SplitStringToIteratorUsing(full, delim, &it); } void SplitStringToSetUsing(const std::string& full, const char* delim, std::set* result) { CHECK(delim != NULL); CHECK(result != NULL); simple_insert_iterator > it(result); SplitStringToIteratorUsing(full, delim, &it); } static void StringAppendV(string* dst, const char* format, va_list ap) { // First try with a small fixed size buffer char space[1024]; // It's possible for methods that use a va_list to invalidate // the data in it upon use. The fix is to make a copy // of the structure before using it and use that copy instead. va_list backup_ap; va_copy(backup_ap, ap); int result = vsnprintf(space, sizeof(space), format, backup_ap); va_end(backup_ap); if ((result >= 0) && (result < sizeof(space))) { // It fit dst->append(space, result); return; } // Repeatedly increase buffer size until it fits int length = sizeof(space); while (true) { if (result < 0) { // Older behavior: just try doubling the buffer size length *= 2; } else { // We need exactly "result+1" characters length = result + 1; } char* buf = new char[length]; // Restore the va_list before we use it again va_copy(backup_ap, ap); result = vsnprintf(buf, length, format, backup_ap); va_end(backup_ap); if ((result >= 0) && (result < length)) { // It fit dst->append(buf, result); delete[] buf; return; } delete[] buf; } } string StringPrintf(const char* format, ...) { va_list ap; va_start(ap, format); string result; StringAppendV(&result, format, ap); va_end(ap); return result; } void SStringPrintf(string* dst, const char* format, ...) { va_list ap; va_start(ap, format); dst->clear(); StringAppendV(dst, format, ap); va_end(ap); } void StringAppendF(string* dst, const char* format, ...) { va_list ap; va_start(ap, format); StringAppendV(dst, format, ap); va_end(ap); } } // namespace network } // namespace dgl