xref: /third_party/skia/include/sksl/DSLFunction.h (revision cb93a386)
1/*
2 * Copyright 2021 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SKSL_DSL_FUNCTION
9#define SKSL_DSL_FUNCTION
10
11#include "include/sksl/DSLBlock.h"
12#include "include/sksl/DSLExpression.h"
13#include "include/sksl/DSLType.h"
14#include "include/sksl/DSLVar.h"
15#include "include/sksl/DSLWrapper.h"
16
17namespace SkSL {
18
19class Block;
20class FunctionDeclaration;
21class Variable;
22
23namespace dsl {
24
25class DSLType;
26
27class DSLFunction {
28public:
29    template<class... Parameters>
30    DSLFunction(const DSLType& returnType, skstd::string_view name, Parameters&... parameters)
31        : DSLFunction(DSLModifiers(), returnType, name, parameters...) {}
32
33    template<class... Parameters>
34    DSLFunction(const DSLModifiers& modifiers, const DSLType& returnType, skstd::string_view name,
35                Parameters&... parameters) {
36        SkTArray<DSLParameter*> parameterArray;
37        parameterArray.reserve_back(sizeof...(parameters));
38
39        // in C++17, we could just do:
40        // (parameterArray.push_back(&parameters), ...);
41        int unused[] = {0, (static_cast<void>(parameterArray.push_back(&parameters)), 0)...};
42        static_cast<void>(unused);
43        // We can't have a default parameter and a template parameter pack at the same time, so
44        // unfortunately we can't capture position info from this overload.
45        this->init(modifiers, returnType, name, std::move(parameterArray), PositionInfo());
46    }
47
48    DSLFunction(const DSLType& returnType, skstd::string_view name,
49                SkTArray<DSLParameter*> parameters, PositionInfo pos = PositionInfo::Capture()) {
50        this->init(DSLModifiers(), returnType, name, std::move(parameters), pos);
51    }
52
53    DSLFunction(const DSLModifiers& modifiers, const DSLType& returnType, skstd::string_view name,
54                SkTArray<DSLParameter*> parameters, PositionInfo pos = PositionInfo::Capture()) {
55        this->init(modifiers, returnType, name, std::move(parameters), pos);
56    }
57
58    DSLFunction(const SkSL::FunctionDeclaration* decl)
59        : fDecl(decl) {}
60
61    virtual ~DSLFunction() = default;
62
63    template<class... Stmt>
64    void define(Stmt... stmts) {
65        DSLBlock block = DSLBlock(DSLStatement(std::move(stmts))...);
66        this->define(std::move(block));
67    }
68
69    void define(DSLBlock block, PositionInfo pos = PositionInfo::Capture());
70
71    /**
72     * Invokes the function with the given arguments.
73     */
74    template<class... Args>
75    DSLExpression operator()(Args&&... args) {
76        ExpressionArray argArray;
77        argArray.reserve_back(sizeof...(args));
78        this->collectArgs(argArray, std::forward<Args>(args)...);
79        return this->call(std::move(argArray));
80    }
81
82    /**
83     * Invokes the function with the given arguments.
84     */
85    DSLExpression call(SkTArray<DSLWrapper<DSLExpression>> args,
86            PositionInfo pos = PositionInfo::Capture());
87
88    DSLExpression call(ExpressionArray args, PositionInfo pos = PositionInfo::Capture());
89
90private:
91    void collectArgs(ExpressionArray& args) {}
92
93    template<class... RemainingArgs>
94    void collectArgs(ExpressionArray& args, DSLVar& var, RemainingArgs&&... remaining) {
95        args.push_back(DSLExpression(var).release());
96        collectArgs(args, std::forward<RemainingArgs>(remaining)...);
97    }
98
99    template<class... RemainingArgs>
100    void collectArgs(ExpressionArray& args, DSLExpression expr, RemainingArgs&&... remaining) {
101        args.push_back(expr.release());
102        collectArgs(args, std::forward<RemainingArgs>(remaining)...);
103    }
104
105    void init(DSLModifiers modifiers, const DSLType& returnType, skstd::string_view name,
106              SkTArray<DSLParameter*> params, PositionInfo pos);
107
108    const SkSL::FunctionDeclaration* fDecl = nullptr;
109    SkSL::PositionInfo fPosition;
110};
111
112} // namespace dsl
113
114} // namespace SkSL
115
116#endif
117