Implement slice expression (#1133)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Bart Louwers <bart@emeel.net>
This commit is contained in:
committed by
GitHub
parent
ecd59d4cc4
commit
09f17c0fc4
@@ -241,6 +241,7 @@ list(APPEND INCLUDE_FILES
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/match.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/number_format.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/parsing_context.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/slice.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/step.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/type.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/value.hpp
|
||||
@@ -641,6 +642,7 @@ list(APPEND SRC_FILES
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/match.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/number_format.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/parsing_context.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/slice.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/step.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/util.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/util.hpp
|
||||
|
||||
@@ -398,6 +398,7 @@ MLN_CORE_SOURCE = [
|
||||
"src/mbgl/style/expression/match.cpp",
|
||||
"src/mbgl/style/expression/number_format.cpp",
|
||||
"src/mbgl/style/expression/parsing_context.cpp",
|
||||
"src/mbgl/style/expression/slice.cpp",
|
||||
"src/mbgl/style/expression/step.cpp",
|
||||
"src/mbgl/style/expression/util.cpp",
|
||||
"src/mbgl/style/expression/util.hpp",
|
||||
@@ -719,6 +720,7 @@ MLN_CORE_HEADERS = [
|
||||
"include/mbgl/style/expression/match.hpp",
|
||||
"include/mbgl/style/expression/number_format.hpp",
|
||||
"include/mbgl/style/expression/parsing_context.hpp",
|
||||
"include/mbgl/style/expression/slice.hpp",
|
||||
"include/mbgl/style/expression/step.hpp",
|
||||
"include/mbgl/style/expression/type.hpp",
|
||||
"include/mbgl/style/expression/value.hpp",
|
||||
|
||||
@@ -179,7 +179,8 @@ enum class Kind : int32_t {
|
||||
In,
|
||||
Within,
|
||||
Distance,
|
||||
IndexOf
|
||||
IndexOf,
|
||||
Slice
|
||||
};
|
||||
|
||||
class Expression {
|
||||
|
||||
39
include/mbgl/style/expression/slice.hpp
Normal file
39
include/mbgl/style/expression/slice.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/expression/expression.hpp>
|
||||
#include <mbgl/style/conversion.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
|
||||
class Slice : public Expression {
|
||||
public:
|
||||
Slice(std::unique_ptr<Expression> input_,
|
||||
std::unique_ptr<Expression> fromIndex_,
|
||||
std::unique_ptr<Expression> toIndex_);
|
||||
|
||||
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
|
||||
|
||||
EvaluationResult evaluate(const EvaluationContext& params) const override;
|
||||
void eachChild(const std::function<void(const Expression&)>&) const override;
|
||||
|
||||
bool operator==(const Expression& e) const override;
|
||||
|
||||
std::vector<std::optional<Value>> possibleOutputs() const override;
|
||||
std::string getOperator() const override;
|
||||
|
||||
private:
|
||||
EvaluationResult evaluateForStringInput(const std::string& input, int fromIndexValue, int toIndexValue) const;
|
||||
EvaluationResult evaluateForArrayInput(const std::vector<Value>& input, int fromIndexValue, int toIndexValue) const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Expression> input;
|
||||
std::unique_ptr<Expression> fromIndex;
|
||||
std::unique_ptr<Expression> toIndex;
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"expression": ["slice", ["array", ["get", "val"]], ["get", "index"]],
|
||||
"inputs": [
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "index": 2}}],
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "index": 0}}],
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "index": 99}}],
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "index": -2}}]
|
||||
],
|
||||
"expected": {
|
||||
"serialized": ["slice", ["array", ["get", "val"]], ["get", "index"]],
|
||||
"compiled": {
|
||||
"result": "success",
|
||||
"isFeatureConstant": false,
|
||||
"isZoomConstant": true,
|
||||
"type": "array"
|
||||
},
|
||||
"outputs": [[3, 4, 5], [1, 2, 3, 4, 5], [], [4, 5]]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"expression": [
|
||||
"slice",
|
||||
["array", ["get", "val"]],
|
||||
["get", "i1"],
|
||||
["get", "i2"]
|
||||
],
|
||||
"inputs": [
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "i1": 2, "i2": 4}}],
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "i1": 1, "i2": 5}}],
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "i1": 1, "i2": 99}}],
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "i1": -4, "i2": -2}}],
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "i1": 0, "i2": -1}}],
|
||||
[{}, {"properties": {"val": [1, 2, 3, 4, 5], "i1": 0, "i2": 0}}]
|
||||
],
|
||||
"expected": {
|
||||
"serialized": [
|
||||
"slice",
|
||||
["array", ["get", "val"]],
|
||||
["get", "i1"],
|
||||
["get", "i2"]
|
||||
],
|
||||
"compiled": {
|
||||
"result": "success",
|
||||
"isFeatureConstant": false,
|
||||
"isZoomConstant": true,
|
||||
"type": "array"
|
||||
},
|
||||
"outputs": [[3, 4], [2, 3, 4, 5], [2, 3, 4, 5], [2, 3], [1, 2, 3, 4], []]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"expression": ["slice", ["get", "input"], ["get", "i1"]],
|
||||
"inputs": [
|
||||
[{}, {"properties": {"input": false, "i1": 1}}],
|
||||
[{}, {"properties": {"input": null, "i1": 1}}],
|
||||
[{}, {"properties": {"input": 12, "i1": 1}}],
|
||||
[{}, {"properties": {"input": {}, "i1": 1}}],
|
||||
[{}, {"properties": {"other": 1, "i1": 1}}],
|
||||
[{}, {"properties": {"input": "correct", "i1": "one"}}]
|
||||
],
|
||||
"expected": {
|
||||
"serialized": ["slice", ["get", "input"], ["get", "i1"]],
|
||||
"compiled": {
|
||||
"result": "success",
|
||||
"isFeatureConstant": false,
|
||||
"isZoomConstant": true,
|
||||
"type": "value"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"error": "Expected first argument to be of type array or string, but found boolean instead."
|
||||
},
|
||||
{
|
||||
"error": "Expected first argument to be of type array or string, but found null instead."
|
||||
},
|
||||
{
|
||||
"error": "Expected first argument to be of type array or string, but found number instead."
|
||||
},
|
||||
{
|
||||
"error": "Expected first argument to be of type array or string, but found object instead."
|
||||
},
|
||||
{
|
||||
"error": "Expected first argument to be of type array or string, but found null instead."
|
||||
},
|
||||
{
|
||||
"error": "Expected value to be of type number, but found string instead."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"expression": ["slice", ["get", "val"], ["get", "index"]],
|
||||
"inputs": [
|
||||
[{}, {"properties": {"val": "0123456789", "index": 0}}],
|
||||
[{}, {"properties": {"val": "0123456789", "index": 4}}],
|
||||
[{}, {"properties": {"val": "0123456789", "index": 99}}],
|
||||
[{}, {"properties": {"val": "0123456789", "index": -2}}]
|
||||
],
|
||||
"expected": {
|
||||
"serialized": ["slice", ["get", "val"], ["get", "index"]],
|
||||
"compiled": {
|
||||
"result": "success",
|
||||
"isFeatureConstant": false,
|
||||
"isZoomConstant": true,
|
||||
"type": "value"
|
||||
},
|
||||
"outputs": ["0123456789", "456789", "", "89"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"expression": ["slice", ["get", "val"], ["get", "i1"], ["get", "i2"]],
|
||||
"inputs": [
|
||||
[{}, {"properties": {"val": "0123456789", "i1": 1, "i2": 8}}],
|
||||
[{}, {"properties": {"val": "0123456789", "i1": 4, "i2": -2}}],
|
||||
[{}, {"properties": {"val": "0123456789", "i1": -3, "i2": -1}}],
|
||||
[{}, {"properties": {"val": "0123456789", "i1": 0, "i2": -1}}],
|
||||
[{}, {"properties": {"val": "0123456789", "i1": 0, "i2": 99}}]
|
||||
],
|
||||
"expected": {
|
||||
"serialized": ["slice", ["get", "val"], ["get", "i1"], ["get", "i2"]],
|
||||
"compiled": {
|
||||
"result": "success",
|
||||
"isFeatureConstant": false,
|
||||
"isZoomConstant": true,
|
||||
"type": "value"
|
||||
},
|
||||
"outputs": ["1234567", "4567", "78", "012345678", "0123456789"]
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ MapLibre welcomes participation and contributions from everyone. Please read [`C
|
||||
## main
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add support for the [`slice` expression](https://maplibre.org/maplibre-style-spec/expressions/#slice) ([#1113](https://github.com/maplibre/maplibre-native/pull/1133))
|
||||
|
||||
- 💥 Breaking: Change package of all classes from `com.mapbox.mapboxsdk` to `org.maplibre.android` ([#1201](https://github.com/maplibre/maplibre-native/pull/1201)). This means you will need to fix your imports.
|
||||
|
||||
|
||||
@@ -1565,7 +1565,7 @@ public class Expression {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first position at which a `needle` can be found in a `haystack`.
|
||||
* Returns the first position at which a `needle` can be found in a `haystack`.
|
||||
*
|
||||
* @param needle the item expression
|
||||
* @param haystack the array or string expression
|
||||
@@ -1577,6 +1577,33 @@ public class Expression {
|
||||
return new Expression("index-of", keyword, input, fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns items from an array or a substring from a string from a specified start index.
|
||||
* The return value is inclusive of the start index.
|
||||
*
|
||||
* @param input the array or string expression
|
||||
* @param fromIndex the index to start slice from
|
||||
* @return array or string
|
||||
* @see <a href="https://maplibre.org/maplibre-style-spec/expressions/#slice">Style specification</a>
|
||||
*/
|
||||
public static Expression slice(@NonNull Expression input, @NonNull Expression fromIndex) {
|
||||
return new Expression("slice", input, fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns items from an array or a substring from a string between a start index and an end index if set.
|
||||
* The return value is inclusive of the start index, but not of the end index.
|
||||
*
|
||||
* @param input the array or string expression
|
||||
* @param fromIndex the index to start slice from
|
||||
* @param toIndex the index to end slice at
|
||||
* @return array or string
|
||||
* @see <a href="https://maplibre.org/maplibre-style-spec/expressions/#slice">Style specification</a>
|
||||
*/
|
||||
public static Expression slice(@NonNull Expression input, @NonNull Expression fromIndex, @NonNull Expression toIndex) {
|
||||
return new Expression("slice", input, fromIndex, toIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves whether an item exists in an array or a substring exists in a string.
|
||||
*
|
||||
|
||||
@@ -477,6 +477,26 @@ class ExpressionTest {
|
||||
Assert.assertTrue("expression should match", Arrays.deepEquals(expected, actual))
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testSlice() {
|
||||
val expected = arrayOf<Any>("slice", arrayOf<Any>("literal", arrayOf<Any>(1f, 2f, 3f)), 1f)
|
||||
val actual =
|
||||
Expression.slice(Expression.literal(arrayOf<Any>(1f, 2f, 3f)), Expression.literal(1f))
|
||||
.toArray()
|
||||
Assert.assertTrue("expression should match", Arrays.deepEquals(expected, actual))
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testSliceWithToIndex() {
|
||||
val expected = arrayOf<Any>("slice", arrayOf<Any>("literal", arrayOf<Any>(1f, 2f, 3f)), 1f, 3f)
|
||||
val actual =
|
||||
Expression.slice(Expression.literal(arrayOf<Any>(1f, 2f, 3f)), Expression.literal(1f), Expression.literal(3f))
|
||||
.toArray()
|
||||
Assert.assertTrue("expression should match", Arrays.deepEquals(expected, actual))
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testInNumber() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
#include <mbgl/style/expression/index_of.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <mbgl/style/expression/step.hpp>
|
||||
#include <mbgl/style/expression/within.hpp>
|
||||
#include <mbgl/style/expression/index_of.hpp>
|
||||
#include <mbgl/style/expression/slice.hpp>
|
||||
|
||||
#include <mbgl/style/expression/find_zoom_curve.hpp>
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
@@ -105,43 +106,42 @@ ParseResult ParsingContext::parse(const Convertible& value,
|
||||
|
||||
using ParseFunction = ParseResult (*)(const conversion::Convertible&, ParsingContext&);
|
||||
MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry =
|
||||
mapbox::eternal::hash_map<mapbox::eternal::string, ParseFunction>({
|
||||
{"==", parseComparison},
|
||||
{"!=", parseComparison},
|
||||
{">", parseComparison},
|
||||
{"<", parseComparison},
|
||||
{">=", parseComparison},
|
||||
{"<=", parseComparison},
|
||||
{"all", All::parse},
|
||||
{"any", Any::parse},
|
||||
{"array", Assertion::parse},
|
||||
{"at", At::parse},
|
||||
{"in", In::parse},
|
||||
{"boolean", Assertion::parse},
|
||||
{"case", Case::parse},
|
||||
{"coalesce", Coalesce::parse},
|
||||
{"collator", CollatorExpression::parse},
|
||||
{"distance", Distance::parse},
|
||||
{"format", FormatExpression::parse},
|
||||
{"image", ImageExpression::parse},
|
||||
{"interpolate", parseInterpolate},
|
||||
{"length", Length::parse},
|
||||
{"let", Let::parse},
|
||||
{"literal", Literal::parse},
|
||||
{"match", parseMatch},
|
||||
{"number", Assertion::parse},
|
||||
{"number-format", NumberFormat::parse},
|
||||
{"object", Assertion::parse},
|
||||
{"step", Step::parse},
|
||||
{"string", Assertion::parse},
|
||||
{"to-boolean", Coercion::parse},
|
||||
{"to-color", Coercion::parse},
|
||||
{"to-number", Coercion::parse},
|
||||
{"to-string", Coercion::parse},
|
||||
{"var", Var::parse},
|
||||
{"within", Within::parse},
|
||||
{"index-of", IndexOf::parse},
|
||||
});
|
||||
mapbox::eternal::hash_map<mapbox::eternal::string, ParseFunction>({{"==", parseComparison},
|
||||
{"!=", parseComparison},
|
||||
{">", parseComparison},
|
||||
{"<", parseComparison},
|
||||
{">=", parseComparison},
|
||||
{"<=", parseComparison},
|
||||
{"all", All::parse},
|
||||
{"any", Any::parse},
|
||||
{"array", Assertion::parse},
|
||||
{"at", At::parse},
|
||||
{"in", In::parse},
|
||||
{"boolean", Assertion::parse},
|
||||
{"case", Case::parse},
|
||||
{"coalesce", Coalesce::parse},
|
||||
{"collator", CollatorExpression::parse},
|
||||
{"distance", Distance::parse},
|
||||
{"format", FormatExpression::parse},
|
||||
{"image", ImageExpression::parse},
|
||||
{"interpolate", parseInterpolate},
|
||||
{"length", Length::parse},
|
||||
{"let", Let::parse},
|
||||
{"literal", Literal::parse},
|
||||
{"match", parseMatch},
|
||||
{"number", Assertion::parse},
|
||||
{"number-format", NumberFormat::parse},
|
||||
{"object", Assertion::parse},
|
||||
{"step", Step::parse},
|
||||
{"string", Assertion::parse},
|
||||
{"to-boolean", Coercion::parse},
|
||||
{"to-color", Coercion::parse},
|
||||
{"to-number", Coercion::parse},
|
||||
{"to-string", Coercion::parse},
|
||||
{"var", Var::parse},
|
||||
{"within", Within::parse},
|
||||
{"index-of", IndexOf::parse},
|
||||
{"slice", Slice::parse}});
|
||||
|
||||
bool isExpression(const std::string& name) {
|
||||
return expressionRegistry.contains(name.c_str());
|
||||
|
||||
156
src/mbgl/style/expression/slice.cpp
Normal file
156
src/mbgl/style/expression/slice.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "mbgl/style/expression/expression.hpp"
|
||||
#include <limits>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
#include <mbgl/style/expression/slice.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
|
||||
namespace {
|
||||
|
||||
int normalizeIndex(int index, int length) {
|
||||
if (index < 0) {
|
||||
index += length;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Slice::Slice(std::unique_ptr<Expression> input_,
|
||||
std::unique_ptr<Expression> fromIndex_,
|
||||
std::unique_ptr<Expression> toIndex_)
|
||||
: Expression(Kind::Slice, input_->getType()),
|
||||
input(std::move(input_)),
|
||||
fromIndex(std::move(fromIndex_)),
|
||||
toIndex(std::move(toIndex_)) {}
|
||||
|
||||
EvaluationResult Slice::evaluate(const EvaluationContext ¶ms) const {
|
||||
const EvaluationResult evaluatedInput = input->evaluate(params);
|
||||
if (!evaluatedInput) {
|
||||
return evaluatedInput.error();
|
||||
}
|
||||
const EvaluationResult evaluatedFromIndex = fromIndex->evaluate(params);
|
||||
if (!fromIndex) {
|
||||
return evaluatedFromIndex.error();
|
||||
}
|
||||
if (!evaluatedFromIndex->is<double>()) {
|
||||
return EvaluationError{"Expected value to be of type number, but found " +
|
||||
toString(typeOf(*evaluatedFromIndex)) + " instead."};
|
||||
}
|
||||
|
||||
int fromIndexValue = static_cast<int>(evaluatedFromIndex->get<double>());
|
||||
int toIndexValue = std::numeric_limits<int>::max();
|
||||
|
||||
if (toIndex) {
|
||||
const EvaluationResult evaluatedToIndex = toIndex->evaluate(params);
|
||||
if (!evaluatedToIndex) {
|
||||
return evaluatedToIndex.error();
|
||||
}
|
||||
if (!evaluatedToIndex->is<double>()) {
|
||||
return EvaluationError{"Expected value to be of type number, but found " +
|
||||
toString(typeOf(*evaluatedFromIndex)) + " instead."};
|
||||
}
|
||||
toIndexValue = static_cast<int>(evaluatedToIndex->get<double>());
|
||||
}
|
||||
|
||||
return evaluatedInput->match(
|
||||
[&](const std::string &s) { return evaluateForStringInput(s, fromIndexValue, toIndexValue); },
|
||||
[&](const std::vector<Value> &v) { return evaluateForArrayInput(v, fromIndexValue, toIndexValue); },
|
||||
[&](const auto &) -> EvaluationResult {
|
||||
return EvaluationError{"Expected first argument to be of type array or string, but found " +
|
||||
toString(typeOf(*evaluatedInput)) + " instead."};
|
||||
});
|
||||
}
|
||||
|
||||
EvaluationResult Slice::evaluateForArrayInput(const std::vector<Value> &array,
|
||||
int fromIndexValue,
|
||||
int toIndexValue) const {
|
||||
int length = static_cast<int>(array.size());
|
||||
if (toIndexValue == std::numeric_limits<int>::max()) {
|
||||
toIndexValue = length;
|
||||
}
|
||||
fromIndexValue = normalizeIndex(fromIndexValue, length);
|
||||
toIndexValue = normalizeIndex(toIndexValue, length);
|
||||
|
||||
if (fromIndexValue >= toIndexValue) {
|
||||
return std::vector<Value>{};
|
||||
}
|
||||
toIndexValue = std::min(toIndexValue, length);
|
||||
|
||||
std::vector<Value> result;
|
||||
result.reserve(toIndexValue - fromIndexValue);
|
||||
for (int index = fromIndexValue; index < toIndexValue; ++index) {
|
||||
result.push_back(array[index]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
EvaluationResult Slice::evaluateForStringInput(const std::string &string, int fromIndexValue, int toIndexValue) const {
|
||||
int length = static_cast<int>(string.size());
|
||||
if (toIndexValue == std::numeric_limits<int>::max()) {
|
||||
toIndexValue = length;
|
||||
}
|
||||
fromIndexValue = normalizeIndex(fromIndexValue, length);
|
||||
toIndexValue = normalizeIndex(toIndexValue, length);
|
||||
if (fromIndexValue >= length) {
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
return string.substr(fromIndexValue, toIndexValue - fromIndexValue);
|
||||
}
|
||||
|
||||
void Slice::eachChild(const std::function<void(const Expression &)> &visit) const {
|
||||
visit(*input);
|
||||
visit(*fromIndex);
|
||||
if (toIndex) {
|
||||
visit(*toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
using namespace mbgl::style::conversion;
|
||||
ParseResult Slice::parse(const Convertible &value, ParsingContext &ctx) {
|
||||
assert(isArray(value));
|
||||
|
||||
std::size_t length = arrayLength(value);
|
||||
if (length != 3 && length != 4) {
|
||||
ctx.error("Expected 2 or 3 arguments, but found " + util::toString(length - 1) + " instead.");
|
||||
return ParseResult();
|
||||
}
|
||||
|
||||
ParseResult input = ctx.parse(arrayMember(value, 1), 1);
|
||||
ParseResult fromIndex = ctx.parse(arrayMember(value, 2), 2);
|
||||
|
||||
ParseResult toIndex = length == 4 ? ctx.parse(arrayMember(value, 3), 3) : ParseResult();
|
||||
|
||||
if (!input || !fromIndex) {
|
||||
return ParseResult();
|
||||
}
|
||||
|
||||
return ParseResult(
|
||||
std::make_unique<Slice>(std::move(*input), std::move(*fromIndex), toIndex ? std::move(*toIndex) : nullptr));
|
||||
}
|
||||
|
||||
bool Slice::operator==(const Expression &e) const {
|
||||
if (e.getKind() == Kind::Slice) {
|
||||
auto rhs = static_cast<const Slice *>(&e);
|
||||
const auto toIndexEqual = (toIndex && rhs->toIndex && *toIndex == *(rhs->toIndex)) ||
|
||||
(!toIndex && !rhs->toIndex);
|
||||
return *input == *(rhs->input) && *fromIndex == *(rhs->fromIndex) && toIndexEqual;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::optional<Value>> Slice::possibleOutputs() const {
|
||||
return {std::nullopt};
|
||||
}
|
||||
|
||||
std::string Slice::getOperator() const {
|
||||
return "slice";
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
Reference in New Issue
Block a user