bool
Parser::Tokenizer::int64 (int64_t & result, int base)
{
- //register uint64_t acc;
- register uint64_t cutoff;
- bool neg = false;
- static SBuf zerox("0x"), zero("0");
-
if (buf_.isEmpty())
return false;
- if (buf_[0] == '-') {
- neg = true;
- buf_.consume(1);
- }
- if (buf_[0] == '+')
- buf_.consume(1);
- if (base == 0) {
- if (buf_.startsWith(zerox))
- base = 16;
- else if (buf_.startsWith(zero))
- base = 8;
- else
- base = 10;
- }
- if (base != 8 && base != 10 && base != 16)
+ // API mismatch with strtoll: we don't eat leading space.
+ if (xisspace(buf_[0]))
return false;
- // TODO: finish
- cutoff = neg ? -(uint64_t) INT64_MIN : INT64_MAX;
+ char *eon;
+ errno = 0; // reset errno
- // dummy to keep compiler happy. Remove before continuing
- if (neg) result = cutoff;
+ int64_t rv = strtoll(buf_.rawContent(), &eon, base);
+
+ if (errno != 0)
+ return false;
+
+ buf_.consume(eon - buf_.rawContent()); // consume the parsed chunk
+ result = rv;
+ return true;
- return false;
}
public:
explicit Tokenizer(const SBuf &inBuf) : buf_(inBuf) {}
+ // return a copy the current contents of the parse buffer
+ const SBuf buf() const { return buf_; }
+
/// whether the end of the buffer has been reached
bool atEnd() const { return buf_.isEmpty(); }
/** parse an unsigned int64_t at the beginning of the buffer
*
- * strtoull(3)-alike function: tries to parse unsigned 64-bit integer
+ * strtoll(3)-alike function: tries to parse unsigned 64-bit integer
* at the beginning of the parse buffer, in the base specified by the user
* or guesstimated; consumes the parsed characters.
*
* the base
* \return true if the parsing was successful
*/
- bool uint64 (uint64_t & result, int base);
-
- bool int64 (int64_t &result, int base);
+ bool int64 (int64_t &result, int base = 0);
private:
SBuf buf_; ///< yet unparsed input
{
}
+
+void
+testTokenizer::testTokenizerInt64()
+{
+ int64_t rv;
+
+ // successful parse in base 10
+ {
+ Parser::Tokenizer t(SBuf("1234"));
+ const int64_t benchmark = 1234;
+ CPPUNIT_ASSERT(t.int64(rv, 10));
+ CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ }
+
+ // successful parse, autodetect base
+ {
+ Parser::Tokenizer t(SBuf("1234"));
+ const int64_t benchmark = 1234;
+ CPPUNIT_ASSERT(t.int64(rv));
+ CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ }
+
+ // successful parse, autodetect base
+ {
+ Parser::Tokenizer t(SBuf("01234"));
+ const int64_t benchmark = 01234;
+ CPPUNIT_ASSERT(t.int64(rv));
+ CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ }
+
+ // successful parse, autodetect base
+ {
+ Parser::Tokenizer t(SBuf("0x12f4"));
+ const int64_t benchmark = 0x12f4;
+ CPPUNIT_ASSERT(t.int64(rv));
+ CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ }
+
+ // API mismatch: don't eat leading space
+ {
+ Parser::Tokenizer t(SBuf(" 1234"));
+ CPPUNIT_ASSERT(!t.int64(rv));
+ }
+
+ // API mismatch: don't eat multiple leading spaces
+ {
+ Parser::Tokenizer t(SBuf(" 1234"));
+ CPPUNIT_ASSERT(!t.int64(rv));
+ }
+
+ // trailing spaces
+ {
+ Parser::Tokenizer t(SBuf("1234 foo"));
+ const int64_t benchmark = 1234;
+ CPPUNIT_ASSERT(t.int64(rv));
+ CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ CPPUNIT_ASSERT_EQUAL(SBuf(" foo"), t.buf());
+ }
+
+ // trailing nonspaces
+ {
+ Parser::Tokenizer t(SBuf("1234foo"));
+ const int64_t benchmark = 1234;
+ CPPUNIT_ASSERT(t.int64(rv));
+ CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ CPPUNIT_ASSERT_EQUAL(SBuf("foo"), t.buf());
+ }
+
+ // trailing nonspaces
+ {
+ Parser::Tokenizer t(SBuf("0x1234foo"));
+ const int64_t benchmark = 0x1234f;
+ CPPUNIT_ASSERT(t.int64(rv));
+ CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ CPPUNIT_ASSERT_EQUAL(SBuf("oo"), t.buf());
+ }
+}