blob: d749810854a35c1d12cee7ebd6d29bed501f28cd [file] [log] [blame]
/**
* 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.
**/
#ifndef QUICKSTEP_EXPRESSIONS_TABLE_GENERATOR_GENERATE_SERIES_HPP_
#define QUICKSTEP_EXPRESSIONS_TABLE_GENERATOR_GENERATE_SERIES_HPP_
#include <string>
#include <vector>
#include "expressions/table_generator/GenerateSeriesHandle.hpp"
#include "expressions/table_generator/GeneratorFunction.hpp"
#include "types/Type.hpp"
#include "types/TypeFactory.hpp"
#include "types/TypeID.hpp"
#include "types/TypedValue.hpp"
#include "types/operations/comparisons/GreaterComparison.hpp"
#include "utility/Macros.hpp"
#include "glog/logging.h"
namespace quickstep {
class GeneratorFunctionHandle;
/** \addtogroup Expressions
* @{
*/
/**
* @brief GeneratorFunction that generates a series of values, from a start
* value to a stop value with a step size.
*/
class GenerateSeries : public GeneratorFunction {
public:
/**
* @brief Singleton instance of the GenerateSeries class.
* @return A const reference to the singleton instance of the GenerateSeries
* class.
*/
static const GenerateSeries& Instance() {
static GenerateSeries instance;
return instance;
}
const std::string getName() const override {
return "generate_series";
}
const std::string getSyntax() const override {
return getName() + "(<start>, <end>[, <step>])";
}
GeneratorFunctionHandle* createHandle(
const std::vector<TypedValue> &arguments) const override {
// Checks arguments and create the function handle for generate_series.
// Arguments should have the pattern (start, end) or (start, end, step).
int arg_size = arguments.size();
if (arg_size != 2 && arg_size != 3) {
throw GeneratorFunctionInvalidArguments("Invalid number of arguments");
}
std::vector<const Type*> arg_types;
for (const TypedValue &arg : arguments) {
if (TypeFactory::TypeRequiresLengthParameter(arg.getTypeID())) {
throw GeneratorFunctionInvalidArguments("Invalid argument types");
}
arg_types.emplace_back(&TypeFactory::GetType(arg.getTypeID()));
}
// Get the unified type of all arguments.
const Type *unified_type = arg_types[0];
for (int i = 1; i < arg_size && unified_type != nullptr; ++i) {
unified_type =
TypeFactory::GetUnifyingType(*arg_types[i],
*unified_type);
}
// Check if the unified type if applicable, then create the handle.
if (unified_type != nullptr) {
TypeID tid = unified_type->getTypeID();
if (tid == TypeID::kInt
|| tid == TypeID::kLong
|| tid == TypeID::kFloat
|| tid == TypeID::kDouble) {
return concretizeWithType(arg_types, arguments, *unified_type);
}
}
throw GeneratorFunctionInvalidArguments("Invalid argument types");
return nullptr;
}
protected:
GenerateSeries() : GeneratorFunction() {
}
private:
GeneratorFunctionHandle* concretizeWithType(
const std::vector<const Type*> &arg_types,
const std::vector<TypedValue> &args,
const Type &type) const {
DCHECK(args.size() == 2 || args.size() == 3);
// Coerce all arguments to the unified type.
TypedValue start = type.coerceValue(args[0], *arg_types[0]);
TypedValue end = type.coerceValue(args[1], *arg_types[1]);
TypedValue step =
args.size() > 2 ? type.coerceValue(args[2], *arg_types[2])
: type.coerceValue(TypedValue(1), TypeFactory::GetType(TypeID::kInt));
// Check that step is not 0, and (end - start) / step is positive
const GreaterComparison &gt_comparator = GreaterComparison::Instance();
bool start_gt_end = gt_comparator.compareTypedValuesChecked(start, type, end, type);
bool step_gt_0 = gt_comparator.compareTypedValuesChecked(
step, type, TypedValue(0), TypeFactory::GetType(TypeID::kInt));
bool step_lt_0 = gt_comparator.compareTypedValuesChecked(
TypedValue(0), TypeFactory::GetType(TypeID::kInt), step, type);
if ((!start_gt_end && step_lt_0) || (start_gt_end && step_gt_0)) {
throw GeneratorFunctionInvalidArguments("Invalid step width");
}
return new GenerateSeriesHandle(getName(), args, type, start, end, step);
}
DISALLOW_COPY_AND_ASSIGN(GenerateSeries);
};
/** @} */
} // namespace quickstep
#endif /* QUICKSTEP_EXPRESSIONS_TABLE_GENERATOR_GENERATE_SERIES_HPP_ */