src/utils/string_splitter.h (174 lines of code) (raw):
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma once
#include <stdlib.h>
#include <stdint.h>
namespace dsn {
enum empty_field_action
{
SKIP_EMPTY_FIELD,
ALLOW_EMPTY_FIELD
};
// Split a string with one character
class string_splitter
{
public:
// Split `input' with `separator'. If `action' is SKIP_EMPTY_FIELD, zero-
// length() field() will be skipped.
inline string_splitter(const char *input,
char separator,
empty_field_action action = SKIP_EMPTY_FIELD);
// Allows containing embedded '\0' characters and separator can be '\0',
// if str_end is not NULL.
inline string_splitter(const char *str_begin,
const char *str_end,
char separator,
empty_field_action = SKIP_EMPTY_FIELD);
// Move splitter forward.
inline string_splitter &operator++();
inline string_splitter operator++(int);
// True iff field() is valid.
inline operator const void *() const;
// Beginning address and length of the field. *(field() + length()) may
// not be '\0' because we don't modify `input'.
inline const char *field() const;
inline size_t length() const;
// Cast field to specific type, and write the value into `pv'.
// Returns 0 on success, -1 otherwise.
// NOTE: If separator is a digit, casting functions always return -1.
inline int to_int8(int8_t *pv) const;
inline int to_uint8(uint8_t *pv) const;
inline int to_int(int *pv) const;
inline int to_uint(unsigned int *pv) const;
inline int to_long(long *pv) const;
inline int to_ulong(unsigned long *pv) const;
inline int to_longlong(long long *pv) const;
inline int to_ulonglong(unsigned long long *pv) const;
inline int to_float(float *pv) const;
inline int to_double(double *pv) const;
private:
inline bool not_end(const char *p) const;
inline void init();
const char *_head;
const char *_tail;
const char *_str_tail;
const char _sep;
const empty_field_action _empty_field_action;
};
string_splitter::string_splitter(const char *str, char sep, empty_field_action action)
: _head(str), _str_tail(NULL), _sep(sep), _empty_field_action(action)
{
init();
}
string_splitter::string_splitter(const char *str_begin,
const char *str_end,
const char sep,
empty_field_action action)
: _head(str_begin), _str_tail(str_end), _sep(sep), _empty_field_action(action)
{
init();
}
void string_splitter::init()
{
// Find the starting _head and _tail.
if (__builtin_expect(_head != NULL, 1)) {
if (_empty_field_action == SKIP_EMPTY_FIELD) {
for (; _sep == *_head && not_end(_head); ++_head) {
}
}
for (_tail = _head; *_tail != _sep && not_end(_tail); ++_tail) {
}
} else {
_tail = NULL;
}
}
string_splitter &string_splitter::operator++()
{
if (__builtin_expect(_tail != NULL, 1)) {
if (not_end(_tail)) {
++_tail;
if (_empty_field_action == SKIP_EMPTY_FIELD) {
for (; _sep == *_tail && not_end(_tail); ++_tail) {
}
}
}
_head = _tail;
for (; *_tail != _sep && not_end(_tail); ++_tail) {
}
}
return *this;
}
string_splitter string_splitter::operator++(int)
{
string_splitter tmp = *this;
operator++();
return tmp;
}
string_splitter::operator const void *() const
{
return (_head != NULL && not_end(_head)) ? _head : NULL;
}
const char *string_splitter::field() const { return _head; }
size_t string_splitter::length() const { return static_cast<size_t>(_tail - _head); }
bool string_splitter::not_end(const char *p) const
{
return (_str_tail == NULL) ? *p : (p != _str_tail);
}
int string_splitter::to_int8(int8_t *pv) const
{
long v = 0;
if (to_long(&v) == 0 && v >= -128 && v <= 127) {
*pv = (int8_t)v;
return 0;
}
return -1;
}
int string_splitter::to_uint8(uint8_t *pv) const
{
unsigned long v = 0;
if (to_ulong(&v) == 0 && v <= 255) {
*pv = (uint8_t)v;
return 0;
}
return -1;
}
int string_splitter::to_int(int *pv) const
{
long v = 0;
if (to_long(&v) == 0 && v >= INT_MIN && v <= INT_MAX) {
*pv = (int)v;
return 0;
}
return -1;
}
int string_splitter::to_uint(unsigned int *pv) const
{
unsigned long v = 0;
if (to_ulong(&v) == 0 && v <= UINT_MAX) {
*pv = (unsigned int)v;
return 0;
}
return -1;
}
int string_splitter::to_long(long *pv) const
{
char *endptr = NULL;
*pv = strtol(field(), &endptr, 10);
return (endptr == field() + length()) ? 0 : -1;
}
int string_splitter::to_ulong(unsigned long *pv) const
{
char *endptr = NULL;
*pv = strtoul(field(), &endptr, 10);
return (endptr == field() + length()) ? 0 : -1;
}
int string_splitter::to_longlong(long long *pv) const
{
char *endptr = NULL;
*pv = strtoll(field(), &endptr, 10);
return (endptr == field() + length()) ? 0 : -1;
}
int string_splitter::to_ulonglong(unsigned long long *pv) const
{
char *endptr = NULL;
*pv = strtoull(field(), &endptr, 10);
return (endptr == field() + length()) ? 0 : -1;
}
int string_splitter::to_float(float *pv) const
{
char *endptr = NULL;
*pv = strtof(field(), &endptr);
return (endptr == field() + length()) ? 0 : -1;
}
int string_splitter::to_double(double *pv) const
{
char *endptr = NULL;
*pv = strtod(field(), &endptr);
return (endptr == field() + length()) ? 0 : -1;
}
} // namespace dsn