blob: d34be5ea4c74e879fde6eeb46f8518dea47a7e05 [file]
/*
* 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 <algorithm>
#include <cctype>
#include <functional>
#include <iterator>
#include <type_traits>
#include "parse_util.h"
#include "status.h"
#include "string_util.h"
#include "type_util.h"
template <typename Iter>
struct MoveIterator : Iter {
explicit MoveIterator(Iter iter) : Iter(iter) {}
typename Iter::value_type&& operator*() const { return std::move(this->Iter::operator*()); }
};
template <typename Iter>
struct CommandParser {
public:
using ValueType = typename Iter::value_type;
static constexpr bool IsRandomAccessIter =
std::is_base_of_v<std::random_access_iterator_tag, typename std::iterator_traits<Iter>::iterator_category>;
CommandParser(Iter begin, Iter end) : begin_(std::move(begin)), end_(std::move(end)) {}
template <typename Container, std::enable_if_t<std::is_lvalue_reference_v<Container> &&
!std::is_same_v<RemoveCVRef<Container>, CommandParser>,
int> = 0>
explicit CommandParser(Container&& con, size_t skip_num = 0) : CommandParser(std::begin(con), std::end(con)) {
std::advance(begin_, skip_num);
}
template <typename Container, std::enable_if_t<!std::is_lvalue_reference_v<Container> &&
!std::is_same_v<RemoveCVRef<Container>, CommandParser>,
int> = 0>
explicit CommandParser(Container&& con, size_t skip_num = 0)
: CommandParser(MoveIterator(std::begin(con)), MoveIterator(std::end(con))) {
std::advance(begin_, skip_num);
}
CommandParser(const CommandParser&) = default;
CommandParser(CommandParser&&) noexcept = default;
CommandParser& operator=(const CommandParser&) = default;
CommandParser& operator=(CommandParser&&) noexcept = default;
~CommandParser() = default;
decltype(auto) RawPeek() const { return *begin_; }
decltype(auto) operator[](size_t index) const {
Iter iter = begin_;
std::advance(iter, index);
return *iter;
}
decltype(auto) RawTake() { return *begin_++; }
decltype(auto) RawNext() { ++begin_; }
bool Good() const { return begin_ != end_; }
std::enable_if_t<IsRandomAccessIter, size_t> Remains() const {
// O(1) iff Iter is random access iterator.
auto d = std::distance(begin_, end_);
CHECK(d >= 0);
return d;
}
size_t Skip(size_t count) {
if constexpr (IsRandomAccessIter) {
size_t steps = std::min(Remains(), count);
begin_ += steps;
return steps;
} else {
size_t steps = 0;
while (count != 0 && Good()) {
++begin_;
++steps;
--count;
}
return steps;
}
}
template <typename Pred>
bool EatPred(Pred&& pred) {
if (Good() && std::forward<Pred>(pred)(RawPeek())) {
RawNext();
return true;
} else {
return false;
}
}
bool EatEqICase(std::string_view str) {
return EatPred([str](const auto& v) { return util::EqualICase(str, v); });
}
bool EatEqICaseFlag(std::string_view str, std::string_view& flag) {
if (str == flag || flag.empty()) {
if (EatEqICase(str)) {
flag = str;
return true;
}
}
return false;
}
StatusOr<ValueType> TakeStr() {
if (!Good()) return {Status::RedisParseErr, "no more item to parse"};
return RawTake();
}
template <typename T = long long, typename... Args>
StatusOr<T> TakeInt(Args&&... args) {
if (!Good()) return {Status::RedisParseErr, "no more item to parse"};
auto res = ParseInt<T>(RawPeek(), std::forward<Args>(args)...);
if (res) {
RawNext();
}
return res;
}
template <typename T = double>
StatusOr<T> TakeFloat() {
if (!Good()) return {Status::RedisParseErr, "no more item to parse"};
auto res = ParseFloat<T>(RawPeek());
if (res) {
RawNext();
}
return res;
}
static Status InvalidSyntax() { return {Status::RedisParseErr, "syntax error"}; }
private:
Iter begin_;
Iter end_;
};
template <typename Container>
CommandParser(const Container&, size_t = 0) -> CommandParser<typename Container::const_iterator>;
template <typename Container>
CommandParser(Container&&, size_t = 0) -> CommandParser<MoveIterator<typename Container::iterator>>;
template <typename Container>
using CommandParserFromConst = CommandParser<typename Container::const_iterator>;