Doxygen 源码分析: QCString类

news/2024/11/19 5:48:57/

2023-05-20 23:41:56
ChrisZZ imzhuo@foxmailcom
Hompage https://github.com/zchrissirhcz

在这里插入图片描述

文章目录

    • 1. Doxygen 版本
    • 2. QCString 类概览
    • 3. QCString 特殊成员函数
      • 3.1 `=default` 方式的构造函数
      • 3.2 单个参数和两个参数的构造函数
    • 4. inline方式实现的成员函数
      • 4.1 operator= 函数
      • 4.2 判断是否为空
      • 4.3 判断长度
      • 4.4 获取裸数据
      • 4.5 调整字符串大小
      • 4.6 用相同字符填充字符串
      • 4.7 删除前缀
      • 4.8 获取子串
      • 4.9 大小写转换
      • 4.10 删除前导和尾部的空格
      • 4.11 引用字符串(quoted string)
      • 4.12 删除全部空白字符
      • 4.13 自我重复n次
      • 4.14 插入字符串
      • 4.15 尾部追加字符
      • 4.16 首部插入字符
      • 4.17 删除若干连续字符
      • 4.18 数字转字符串
      • 4.19 判断是否以某个字符串开头、结尾
      • 4.20 获取裸数据
      • 4.21 字符串拼接:operator+= 操作符函数
      • 4.22 获取字符
    • 5. 非 inline 方式实现的成员函数
      • 5.1 格式化字符串
      • 5.2 查找字符
      • 5.3. 查找字符串
      • 5.4 反向查找
      • 5.4 检查是否存在字符
      • 5.5 检查是否存在字符串子串
      • 5.6 简化空格
      • 5.7 替换子串
      • 5.8 转为数字

1. Doxygen 版本

本次使用的 doxygen 版本如下, 是 1.9.8 正式发布版本对应的 commit

$ git log
commit 5fded4215d4f9271fe92c940fc4532d4704f5be1 (HEAD -> master, upstream/master)
Author: Dimitri van Heesch <doxygen@gmail.com>
Date:   Thu May 18 22:14:30 2023 +0200bump version to 1.9.8 for development

2. QCString 类概览

通过前文 Doxygen源码分析:构建过程简介,并生成doxygen自身的C++文档 生成的 Doxygen C++ 文档, 可以查询得到 QCString 类的文档网页:
在这里插入图片描述

相关文件:

  • qcstring.h
  • qcstring.cpp
  • utf8.h
  • utf8.cpp

3. QCString 特殊成员函数

这里用“特殊成员函数”表示“没有返回值的成员函数”, 基本上是构造函数。

3.1 =default 方式的构造函数

首先是使用了 C++11 中增加 =default 用法的几个:

    QCString() = default;~QCString() = default;QCString( const QCString &s ) = default;QCString &operator=( const QCString &s ) = default;QCString( QCString &&s ) = default;QCString &operator=( QCString &&s ) = default;

3.2 单个参数和两个参数的构造函数

其次是传入单个参数, 赋值给到 m_rep 成员的:

    explicit QCString( const std::string &s ) : m_rep(s) {}QCString( std::string &&s) : m_rep(std::move(s)) {}

其中 m_rep 的定义如下:

  private:std::string m_rep;

构造函数也可以传入 size, 如果 size 大于0则让 m_rep 执行 resize 到 size-1 的大小, 否则大小置为0:

    /** creates a string with room for size characters*  @param[in] size the number of character to allocate (also counting the 0-terminator!)*/explicit QCString( size_t size ) { m_rep.resize(size>0 ? size-1 : 0); }

其中 std::string 类的 resize 方法,可以在 https://en.cppreference.com/w/cpp/string/basic_string/resize 找到解释:

  • void resize( size_type count )
  • 如果 m_rep 当前长度小于 count, 则继续填充 CharT() 字符, 对于 std::string 而言就是 \0 字符,直到到达 count 个字符
  • 如果 m_rep 当前长度超过 count, 则砍掉多余的字符

也可以从 C 字符串初始化 m_rep:

    /** creates a string from a plain C string.*  @param[in] str A zero terminated C string. When 0 an empty string is created.*/QCString( const char *str ) : m_rep(str?str:"") {}

还可以指定 str 和 maxlen 两个参数, 从 str 的前 maxlen 个字符执行拷贝来初始化 m_rep:

    /** creates a string from \a str and copies over the first \a maxlen characters. */QCString( const char *str, size_t maxlen ) : m_rep(str?str:"") { m_rep.resize(maxlen); }

4. inline方式实现的成员函数

在 QCString 的 class body 内直接定义(实现)的函数。 比较短小。

4.1 operator= 函数

传入一个 C 字符串指针 或 std::string 对象, 用来替代 m_rep 的值:

    /** replaces the contents by that of C string \a str. */QCString &operator=( const char *str) { m_rep = str?str:""; return *this; }QCString &operator=( const std::string &s) { m_rep = s; return *this; }

4.2 判断是否为空

    /** Returns TRUE iff the string is empty. Equivalent to isEmpty(). */bool isNull() const { return m_rep.empty(); }/** Returns TRUE iff the string is empty */bool isEmpty() const { return m_rep.empty(); }

4.3 判断长度

    /** Returns the length of the string, not counting the 0-terminator. Equivalent to size(). */uint32_t length() const { return static_cast<uint32_t>(m_rep.size()); }/** Returns the length of the string, not counting the 0-terminator. */uint32_t size() const { return static_cast<uint32_t>(m_rep.size()); }

4.4 获取裸数据

    /** Returns a pointer to the contents of the string in the form of a 0-terminated C string */const char *data() const { return m_rep.c_str(); }/** Returns a writable pointer to the data.*/char *rawData() { return &m_rep[0]; }

4.5 调整字符串大小

resize: 增加字符串尺寸, 或减小尺寸

    /** Resizes the string to hold \a newlen characters*  (this value should also count the 0-terminator).*  If the string is enlarged the contents will*  be left unmodified.*/bool resize( size_t newlen ) { m_rep.resize( newlen>0 ? newlen-1 : 0 ); return TRUE; }

truncate: 英文本意是截断, 这里其实允许 pos 大于现有长度, 于是是将字符串长度增大:

    /** Truncates the string at position \a pos. */bool truncate( size_t pos ) { return resize( pos + 1 ); }

reserve: 修改预留空间大小, 也就是改变 capacity, 但不改变 size

    /** Reserve space for \a size bytes without changing the string contents */void reserve( size_t size ) { m_rep.reserve(size); }

4.6 用相同字符填充字符串

会覆盖替换原有内容:

    /** Fills a string with a predefined character*  @param[in] c the character used to fill the string with.*  @param[in] len the number of character to fill. Use -1 to fill the whole string.*  @note the string will be resized to contain \a len characters. The contents of the*  string will be lost.*/bool fill( char c, int len = -1 ){int l = len==-1 ? static_cast<int>(m_rep.size()) : len;m_rep = std::string(l,c);return TRUE;}

4.7 删除前缀

如果 m_rep 的前面 n 个长度的子串等于 prefix, 那就删除它们, 返回 true; 其他情况返回 false:

    bool stripPrefix(const QCString &prefix){if (prefix.isEmpty() || m_rep.empty()) return FALSE;if (m_rep.rfind(prefix.data(),0)==0) // string starts with prefix{m_rep.erase(0,prefix.length());return TRUE;}return FALSE;}bool stripPrefix(const char *prefix){return stripPrefix(QCString(prefix));}

4.8 获取子串

获取左子串: 给定长度 len, 获取 m_rep 的左边 len 个字符组成的 QCString:

    QCString left( size_t len ) const{return m_rep.empty() ? QCString() : QCString(m_rep.substr(0,len));}

获取右子串: 类似于左子串:

    QCString right( size_t len ) const{return m_rep.empty()    ? QCString() :len<m_rep.size() ? QCString(m_rep.substr(m_rep.size()-len,len)) :*this;}

获取中间子串: 需要给出起始索引位置 index, 从 index 开始的 len 个字符作为构成结果字符串的元素:

    QCString mid( size_t index, size_t len=static_cast<size_t>(-1)) const{size_t slen = m_rep.size();if (len==static_cast<uint32_t>(-1)) len = slen-index;return m_rep.empty() || index>slen || len==0 ? QCString() :QCString(m_rep.substr(index,len));}

4.9 大小写转换

字符串转小写, 依赖了 utf8.hutf8.cpp 中的函数:

    QCString lower() const{return QCString(convertUTF8ToLower(m_rep));}QCString upper() const{return QCString(convertUTF8ToUpper(m_rep));}

utf8.cpp 中的代码略复杂, 本篇不做分析:

std::string convertUTF8ToLower(const std::string &input)
{return caseConvert(input,asciiToLower,convertUnicodeToLower);
}std::string convertUTF8ToUpper(const std::string &input)
{return caseConvert(input,asciiToUpper,convertUnicodeToUpper);
}

4.10 删除前导和尾部的空格

使用到了前一篇 Doxygen源码分析: QCString类依赖的qstr系列C函数浅析 分析过的 qisspace() 函数, 主要思路是双指针, 也即:判断前导空格结束的位置记录为 start, 从后往前判断空格得到尾部连续空格得第一个位置的前面一个索引位置 end。 然后用 substr 方法获取结果。

    /// returns a copy of this string with leading and trailing whitespace removedQCString stripWhiteSpace() const{size_t sl = m_rep.size();if (sl==0 || (!qisspace(m_rep[0]) && !qisspace(m_rep[sl-1]))) return *this;size_t start=0,end=sl-1;while (start<sl && qisspace(m_rep[start])) start++;if (start==sl) return QCString(); // only whitespacewhile (end>start && qisspace(m_rep[end])) end--;return QCString(m_rep.substr(start,1+end-start));}

4.11 引用字符串(quoted string)

将 QCString 转为引用方式的字符串:

  • 去掉前导和尾部的空格(好奇为什么不通过调用StripWiteSpace实现);
  • 扫描剩余的字符, 如果存在 - 字符, 或者存在空格, 则判定为需要引号
  • 如果需要引号, 就在去掉了前后空格后的字符串的开头、结尾增加引号
    // Returns a quoted copy of this string, unless it is already quoted.// Note that trailing and leading whitespace is removed.QCString quoted() const{size_t start=0, sl=m_rep.size(), end=sl-1;while (start<sl && qisspace(m_rep[start])) start++; // skip over leading whitespaceif (start==sl) return QCString(); // only whitespacewhile (end>start && qisspace(m_rep[end]))   end--;   // skip over trailing whitespacebool needsQuotes=false;size_t i=start;if (i<end && m_rep[i]!='"') // stripped string has at least non-whitespace unquoted character{while (i<end && !needsQuotes) // check if the to be quoted part has at least one whitespace character{needsQuotes = m_rep[i] =='-';needsQuotes |= qisspace(m_rep[i++]);}}QCString result(m_rep.substr(start,1+end-start));if (needsQuotes){result.prepend("\"");result.append("\"");}return result;}

可以简单验证下:

    printf("Hello, World!\n");QCString s = "Hello World";std::cout << s.quoted() << std::endl;QCString t = "Hello-World";std::cout << t.quoted() << std::endl;

将输出:

“Hello World”
“Hello-World”

4.12 删除全部空白字符

对原有字符串逐个判断, 不是空格,则执行拷贝,空格则跳过。

对于拷贝动作来说, 没有新创建字符串, 是在原字符串上就地执行的, 因而节省了内存。

具体实现如下:

    /// returns a copy of this string with all whitespace removedQCString removeWhiteSpace() const{size_t sl = m_rep.size();if (sl==0) return *this;std::string result = m_rep;size_t src=0,dst=0;while (src<sl){if (!qisspace(m_rep[src])) result[dst++]=m_rep[src];src++;}if (dst<m_rep.size()) result.resize(dst);return QCString(result);}

4.13 自我重复n次

将原有字符串内容重复n次,复制到新的字符串中并返回:

    // Returns a copy of this string repeated n timesQCString repeat(unsigned int n) const{QCString result(n * size() + 1);size_t offset = 0;for (offset = 0; offset < n * size(); offset += size()){memcpy(result.rawData() + offset, data(), size());}return result;}

4.14 插入字符串

    QCString &insert( size_t index, const QCString &s ){if (s.length()>0){size_t ol = m_rep.size();if (index>ol) // insert beyond end of string and fill gap with spaces{m_rep.resize(index+s.length());std::memset(&m_rep[ol],' ',index-ol);std::memcpy(&m_rep[index],s.data(),s.length()+1);}else // insert inside the string{m_rep.insert(index,s.str());}}return *this;}QCString &insert( size_t index, const char *s ){size_t len = s ? qstrlen(s) : 0;if (len>0){size_t ol = m_rep.size();if (index>ol) // insert beyond end of string and fill gap with spaces{m_rep.resize(index+len);std::memset(&m_rep[ol],' ',index-ol);std::memcpy(&m_rep[index],s,len+1);}else // insert inside the string{m_rep.insert(index,s);}}return *this;}QCString &insert( size_t index, char c){char s[2] = { c, '\0' };return insert(index,s);}

4.15 尾部追加字符

    QCString &append( char c){m_rep+=c;return *this;}QCString &append( const char *s ){return operator+=(s);}QCString &append( const QCString &s ){return operator+=(s);}QCString &append( const std::string &s ){return operator+=(s);}QCString &prepend( const char *s ){return insert(0,s);}

4.16 首部插入字符

    QCString &prepend( const QCString &s ){return insert(0,s.data());}QCString &prepend( const std::string &s ){return insert(0,s.c_str());}

4.17 删除若干连续字符

    QCString &remove( size_t index, size_t len ){size_t ol = m_rep.size();if (index<ol && len>0) m_rep.erase(index,index+len>=ol ? std::string::npos : len);return *this;}

4.18 数字转字符串

使用C++11的 std::to_string() 实现的:

    QCString &setNum(short n){m_rep = std::to_string(n);return *this;}QCString &setNum(uint16_t n){m_rep = std::to_string(n);return *this;}QCString &setNum(int n){m_rep = std::to_string(n);return *this;}QCString &setNum(uint32_t n){m_rep = std::to_string(n);return *this;}QCString &setNum(long n){m_rep = std::to_string(n);return *this;}QCString &setNum(long long n){m_rep = std::to_string(n);return *this;}QCString &setNum(unsigned long long n){m_rep = std::to_string(n);return *this;}QCString &setNum(unsigned long n){m_rep = std::to_string(n);return *this;}

4.19 判断是否以某个字符串开头、结尾

Python 用户一定很熟悉这个 API。 使用 std::string 的 rfind 和 compare 实现的:

    bool startsWith( const char *s ) const{if (m_rep.empty() || s==0) return s==0;return m_rep.rfind(s,0)==0; // looking "backward" starting and ending at index 0}bool startsWith( const QCString &s ) const{if (m_rep.empty() || s.isEmpty()) return s.isEmpty();return m_rep.rfind(s.str(),0)==0; // looking "backward" starting and ending at index 0}bool endsWith(const char *s) const{if (m_rep.empty() || s==0) return s==0;size_t l = strlen(s);return m_rep.length()>=l && m_rep.compare(m_rep.length()-l, l, s, l)==0;}bool endsWith(const QCString &s) const{size_t l = s.length();return m_rep.length()>=l && m_rep.compare(m_rep.length()-l, l, s.str())==0;}

4.20 获取裸数据

#define HAS_IMPLICIT_CAST_TO_PLAIN_C_STRING 0
#if HAS_IMPLICIT_CAST_TO_PLAIN_C_STRING/** Converts the string to a plain C string */operator const char *() const{return data();}
#endifconst std::string &str() const{return m_rep;}

4.21 字符串拼接:operator+= 操作符函数

直接调用 std::string 的 += 实现的:

    QCString &operator+=( const QCString &s){m_rep+=s.str();return *this;}QCString &operator+=( const std::string &s){m_rep+=s;return *this;}/** Appends string \a str to this string and returns a reference to the result. */QCString &operator+=( const char *s ){if (s) m_rep+=s;return *this;}#define HAS_CHARACTER_APPEND_OPERATOR 1
#if HAS_CHARACTER_APPEND_OPERATOR/** Appends character \a c to this string and returns a reference to the result. */QCString &operator+=( char c ){m_rep+=c;return *this;}
#endif

4.22 获取字符

不执行索引是否非法的安全检查。提供 at()operator[] 两类函数, 每类函数提供 const 和 非const 的版本:

    /** Returns a reference to the character at index \a i. */char &at( size_t i){return m_rep[i];}const char &at( size_t i) const{return m_rep[i];}/** Indexing operator. Equivalent to at(). */char &operator[]( int i ){return m_rep[i];}const char &operator[]( int i ) const{return m_rep[i];}

5. 非 inline 方式实现的成员函数

5.1 格式化字符串

QCString &sprintf( const char *format, ... );QCString &QCString::sprintf( const char *format, ... )
{va_list ap;va_start( ap, format );const int minlen=256;int l = length();if (l<minlen) { resize(minlen); l=minlen; }int n=vsnprintf( rawData(), l, format, ap);if (n<0) n=l;resize(n+1);va_end( ap );return *this;
}

5.2 查找字符

c 表示需要找的字符, index 表示起始索引, cs 表示是否 case sensitive.

int	find( char c, int index=0, bool cs=TRUE ) const;int QCString::find( char c, int index, bool cs ) const
{if (index<0 || index>=static_cast<int>(length())) return -1; // index outside stringconst char *pos;if (cs){pos = strchr(data()+index,c);}else{pos = data()+index;c = toLowerChar(c);while (*pos && toLowerChar(*pos)!=c) pos++;if (!*pos && c) pos=0; // not found}return pos ? static_cast<int>(pos - data()) : -1;
}

如果没找到, 则给 pos 指针赋值为0。用 nullptr 会有更好的可读性。

5.3. 查找字符串

使用了 qstrnicmpstrstr 函数来处理大小写不敏感、大小写敏感的两种情况。

int	find( const char *str, int index=0, bool cs=TRUE ) const;
int find( const QCString &str, int index=0, bool cs=TRUE ) const;
//int	find( const QRegExp &rx, int index=0 ) const;int QCString::find( const char *str, int index, bool cs ) const
{int l = length();if (index<0 || index>=l) return -1; // index outside stringif (!str)  return -1;               // no string to search forif (!*str) return index;           // empty string matching at indexconst char *pos;if (cs) // case sensitive{pos = strstr(data()+index,str);}else // case insensitive{pos = data();int len = qstrlen(str);while (*pos){if (qstrnicmp(pos,str,len)==0) break;pos++;}if (!*pos) pos = 0; // not found}return pos ? static_cast<int>(pos - data()) : -1;
}int QCString::find( const QCString &str, int index, bool cs ) const
{return find(str.data(),index,cs);
}

没找到结果时, 给 pos 指针赋值为0, 改为 nullptr 更合理。

5.4 反向查找

strrchr() 是C语言标准库里的函数:https://en.cppreference.com/w/c/string/byte/strrchr

  • 反向查找第一个出现的给定字符
  • 支持查找 \0 字符, \0 被当做字符串的一部分使用

QString::findRev() 基于 strrstr() 进行查找, 用于大小写不敏感的情况。
此外, QString::findRev() 还支持 index 为负数。

int	findRev( char c, int index=-1, bool cs=TRUE) const;
int	findRev( const char *str, int index=-1, bool cs=TRUE) const;
//int	findRev( const QRegExp &rx, int index=-1 ) const;int QCString::findRev( char c, int index, bool cs) const
{const char *b = data();const char *pos;int len = length();if (len==0) return -1; // empty stringif (index<0) // start from end{if (cs){pos = strrchr(b,c);return pos ? static_cast<int>(pos - b) : -1;}index=len;}else if (index>len) // bad index{return -1;}pos = b+index;if (cs){while ( pos>=b && *pos!=c) pos--;}else{c = toLowerChar(c);while ( pos>=b && toLowerChar(*pos)!=c) pos--;}return pos>=b ? static_cast<int>(pos - b) : -1;
}int QCString::findRev( const char *str, int index, bool cs) const
{int slen = qstrlen(str);int len = length();if (index<0) index = len-slen; // start from endelse if (index>len) return -1; // bad indexelse if (index+slen>len) index=len-slen; // str would be too longif (index<0) return -1; // no match possibleconst char *pos = data()+index;if (cs) // case sensitive{for (int i=index; i>=0; i--) if (qstrncmp(pos--,str,slen)==0) return i;}else // case insensitive{for (int i=index; i>=0; i--) if (qstrnicmp(pos,str,slen)==0) return i;}return -1;
}

5.4 检查是否存在字符

  • 支持大小写敏感的参数设定
  • 如果字符串长度为0, 返回0
  • 如果字符串长度不为0, 则返回找到给定字符 c 的出现次数
int	contains( char c, bool cs=TRUE ) const;int QCString::contains( char c, bool cs ) const
{if (length()==0) return 0;int count=0;const char *pos = data();if (cs){while (*pos) if (*pos++ == c) count++;}else{c = toLowerChar(c);while (*pos){if (toLowerChar(*pos)==c) count++;pos++;}}return count;
}

5.5 检查是否存在字符串子串

基于先前实现的 C 函数 qstrncmp()qstrnicmp() 实现。

int	contains( const char *str, bool cs=TRUE ) const;
//int contains( const QRegExp &rx ) const;int QCString::contains( const char *str, bool cs ) const
{if (str==0 || length()==0) return 0;int count=0;const char *pos = data();int len = qstrlen(str);while (*pos){if (cs){if (qstrncmp(pos,str,len)==0) count++;}else{if (qstrnicmp(pos,str,len)==0) count++;}pos++;}return count;
}

5.6 简化空格

简化有两方面:

  • 去掉了前导的所有空格
  • 去掉了结尾的所有空格
  • 对于剩余部分的字符串
    • 如果不是空格,则原样拷贝
    • 如果是空格, 连续的空格仅拷贝一个, 其他跳过
/// return a copy of this string with leading and trailing whitespace removed and multiple
/// whitespace characters replaced by a single space
QCString simplifyWhiteSpace() const;QCString QCString::simplifyWhiteSpace() const
{if ( isEmpty() )                            // nothing to doreturn *this;QCString result( length()+1 );const char *from  = data();char *to    = result.rawData();char *first = to;while ( TRUE ){while ( *from && qisspace(*from) )from++;while ( *from && !qisspace(*from) )*to++ = *from++;if ( *from )*to++ = 0x20;                       // ' 'elsebreak;}if ( to > first && *(to-1) == 0x20 )to--;*to = '\0';result.resize( static_cast<int>(to - result.data()) + 1 );return result;
}

作为验证:

    QCString s = "  Hello  World    ";std::cout << "[" << s.simplifyWhiteSpace() << "]" << std::endl;

输出内容如下:

Hello, World!
[Hello World]

5.7 替换子串

这里的实现比较偷懒, 感觉效率也不会很高。
首先调用了 remove, 而 remove 其实是调用 m_rep.erase, 会生成新的字符串。
然后调用了 insert, insert 的位置决定了基本上是要新创建字符串的。

也就是说需要两次创建字符串, 其实可以只创建一次。。

QCString &replace( size_t index, size_t len, const char *s);
//QCString &replace( const QRegExp &rx, const char *str );QCString &QCString::replace( size_t index, size_t len, const char *s)
{remove( index, len );insert( index, s );return *this;
}

5.8 转为数字

这一部分代码略多, 其实可以考虑用 C++11 转换函数进行替代:

  • std::stoi() 替代 toInt()
  • std::stol() 替代 toLong()
  • std::stoll() 替代 toInt64()
  • std::stoul() 替代 toULong()
    short         toShort(  bool *ok=0, int base=10 ) const;uint16_t      toUShort( bool *ok=0, int base=10 ) const;int	          toInt(    bool *ok=0, int base=10 ) const;uint32_t      toUInt(   bool *ok=0, int base=10 ) const;long          toLong(   bool *ok=0, int base=10 ) const;unsigned long toULong(  bool *ok=0, int base=10 ) const;uint64_t      toUInt64( bool *ok=0, int base=10 ) const;short QCString::toShort(bool *ok, int base) const
{long v = toLong( ok, base );if ( ok && *ok && (v < -32768 || v > 32767) ) {*ok = FALSE;v = 0;}return static_cast<short>(v);
}uint16_t QCString::toUShort(bool *ok,int base) const
{unsigned long v = toULong( ok, base );if ( ok && *ok && (v > 65535) ) {*ok = FALSE;v = 0;}return static_cast<uint16_t>(v);
}int QCString::toInt(bool *ok, int base) const
{return static_cast<int>(toLong( ok, base ));
}uint32_t QCString::toUInt(bool *ok,int base) const
{return static_cast<uint32_t>(toULong( ok, base ));
}long QCString::toLong(bool *ok,int base) const
{const char *p = data();long val=0;int l = length();const long max_mult = INT_MAX / base;bool is_ok = FALSE;int neg = 0;if ( !p )goto bye;while ( l && qisspace(*p) )			// skip leading spacel--,p++;if ( l && *p == '-' ) {l--;p++;neg = 1;} else if ( *p == '+' ) {l--;p++;}// NOTE: toULong() code is similarif ( !l || !ok_in_base(*p,base) )goto bye;while ( l && ok_in_base(*p,base) ) {l--;int dv;if ( *p>='0' && *p<='9' ) {dv = *p-'0';} else {if ( *p >= 'a' && *p <= 'z' )dv = *p - 'a' + 10;elsedv = *p - 'A' + 10;}if ( val > max_mult || (val == max_mult && dv > (INT_MAX%base)+neg) )goto bye;val = base*val + dv;p++;}if ( neg )val = -val;while ( l && qisspace(*p) )			// skip trailing spacel--,p++;if ( !l )is_ok = TRUE;
bye:if ( ok )*ok = is_ok;return is_ok ? val : 0;
}unsigned long QCString::toULong(bool *ok,int base) const
{const char *p = data();unsigned long val=0;int l = length();const unsigned long max_mult = 429496729;		// UINT_MAX/10, rounded downbool is_ok = FALSE;if ( !p )goto bye;while ( l && qisspace(*p) )			// skip leading spacel--,p++;if ( *p == '+' )l--,p++;// NOTE: toLong() code is similarif ( !l || !ok_in_base(*p,base) )goto bye;while ( l && ok_in_base(*p,base) ) {l--;uint32_t dv;if ( *p>='0' && *p<='9' ) {dv = *p-'0';} else {if ( *p >= 'a' && *p <= 'z' )dv = *p - 'a' + 10;elsedv = *p - 'A' + 10;}if ( val > max_mult || (val == max_mult && dv > (UINT_MAX%base)) )goto bye;val = base*val + dv;p++;}while ( l && qisspace(*p) )			// skip trailing spacel--,p++;if ( !l )is_ok = TRUE;
bye:if ( ok )*ok = is_ok;return is_ok ? val : 0;
}uint64_t QCString::toUInt64(bool *ok,int base) const
{const char *p = data();uint64_t val=0;int l = length();const uint64_t max_mult = 1844674407370955161ULL;  // ULLONG_MAX/10, rounded downbool is_ok = FALSE;if ( !p )goto bye;while ( l && qisspace(*p) )		 	   // skip leading spacel--,p++;if ( *p == '+' )l--,p++;// NOTE: toULong() code is similarif ( !l || !ok_in_base(*p,base) )goto bye;while ( l && ok_in_base(*p,base) ) {l--;uint32_t dv;if ( *p>='0' && *p<='9' ) {dv = *p-'0';} else {if ( *p >= 'a' && *p <= 'z' )dv = *p - 'a' + 10;elsedv = *p - 'A' + 10;}if ( val > max_mult || (val == max_mult && dv > (ULLONG_MAX%base)) )goto bye;val = base*val + dv;p++;}while ( l && qisspace(*p) )			// skip trailing spacel--,p++;if ( !l )is_ok = TRUE;
bye:if ( ok )*ok = is_ok;return is_ok ? val : 0;
}

http://www.ppmy.cn/news/75811.html

相关文章

Java Springboot下redis用pipelining管道模式写入性能调优实例讲解

Springboot下redis写入pipelining管道模式性能调优实例 一、真实场景 生产真实项目过程中&#xff0c;需要将数据库的数据同步写入redis&#xff0c;此过程中遇到写入redis的瓶颈。每次启动项目都要将数据库数据重载到redis&#xff0c;这个过程耗费了大量的时间。 二、解决…

内网渗透(八十一)之搭建Exchange服务器

搭建Exchange服务器 环境安装准备 1、Windows Server 2012 R2以管理员身份运行Windows Powershell,安装必需的 Windows组件: Install-WindowsFeature NET-Framework-45-Features, Server-Media-Foundation, RPC-over-HTTP-proxy, RSAT-Clustering, RSAT-Clustering-CmdInt…

WorkPlus AI助理 | 将企业业务场景与ChatGPT结合

近年来&#xff0c;人工智能成为了企业数字化转型的热门话题&#xff0c;作为被训练的语言模型&#xff0c;ChatGPT具备模拟对话、回答问题、写代码、写小说、进行线上内容创作的能力&#xff0c;还能根据聊天的上下文进行互动。作为一款新兴的人工智能应用程序&#xff0c;对于…

Ae:跟踪运动

使用跟踪器 Tracker面板的跟踪运动 Track Motion功能&#xff0c;可通过手动添加和设置跟踪点来跟踪对象的运动&#xff0c;并能将获得的跟踪数据应用于其它对象。 Ae菜单&#xff1a;窗口/跟踪器 Tracker 点击跟踪器面板上的“跟踪运动”按钮&#xff0c;会为图层添加“动态跟…

Ansible变量 机密 事实

ansible 1.是基于python开发的运维自动化工具 2.基于模块运行&#xff0c;本身没有批量部署的能力&#xff0c;只提供批量部署的框架 3.使用ssh网络协议与受管节点通信 4.架构是无代理 简述 章2 ansible清单 1.清单概念 清单内容是&#xff1a;ansible管理的主机 清单有静态清…

linux 安装 maven 3.8 版本

文章目录 1&#xff1a;maven 仓库官网 2、下载安装包 3、使用&#xff1a;Xftp 上传到你想放的目录 4、解压文件 ​编辑 5、配置环境变量 ​编辑 6、刷新 /etc/profile 文件 7、查看maven 版本 1&#xff1a;maven 仓库官网 Maven – Download Apache Mavenhttps://mave…

做亚马逊会遇到哪些坑?

第一个坑&#xff0c;不要迷信可以无脑铺货 不要听服务商告诉你的&#xff0c;只有店铺产品足够了&#xff0c;才会有订单&#xff0c;才能爆单。这种人是不懂的。因为在亚马逊自己送货实际上比联邦快&#xff0c;难多了。首先&#xff0c;大规模的铺货容易侵权&#xff0c;还…

【c语言】二进制文件的读写操作

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c语言系列专栏&#xff1a;c语言之路重点知识整合 &#x…