Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1087)

Unified Diff: sandbox/linux/bpf_dsl/bpf_dsl.h

Issue 438683004: bpf_dsl: support Switch/Case expressions (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync and resolve conflicts Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | sandbox/linux/bpf_dsl/bpf_dsl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sandbox/linux/bpf_dsl/bpf_dsl.h
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl.h b/sandbox/linux/bpf_dsl/bpf_dsl.h
index b46d1adb113afa0b60fd51b0e17f26331d124663..0664d516147d202d1d0fdde40a775be266f9fbce 100644
--- a/sandbox/linux/bpf_dsl/bpf_dsl.h
+++ b/sandbox/linux/bpf_dsl/bpf_dsl.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <utility>
+#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -59,10 +60,12 @@ class SandboxBPF;
//
// More generally, the DSL currently supports the following grammar:
//
-// result = Allow() | Error(errno) | Trap(trap_func, arg)
+// result = Allow() | Error(errno) | Trap(trap_func, aux)
// | If(bool, result)[.ElseIf(bool, result)].Else(result)
-// bool = arg == val | (arg & mask) == val
-// | !bool | bool && bool | bool || bool
+// | Switch(arg)[.Case(val, result)].Default(result)
+// bool = BoolConst(boolean) | !bool | bool && bool | bool || bool
+// | arg == val
+// arg = Arg<T>(num) | arg & mask
//
// The semantics of each function and operator are intended to be
// intuitive, but are described in more detail below.
@@ -76,6 +79,8 @@ namespace bpf_dsl {
// Forward declarations of classes; see below for proper documentation.
class Elser;
+template <typename T>
+class Caser;
namespace internal {
class ResultExprImpl;
class BoolExprImpl;
@@ -159,6 +164,9 @@ class SANDBOX_EXPORT Arg {
DISALLOW_ASSIGN(Arg);
};
+// Convert a bool value into a BoolExpr.
+SANDBOX_EXPORT BoolExpr BoolConst(bool value);
+
// Various ways to combine boolean expressions into more complex expressions.
// They follow standard boolean algebra laws.
SANDBOX_EXPORT BoolExpr operator!(const BoolExpr& cond);
@@ -190,9 +198,62 @@ class SANDBOX_EXPORT Elser {
Cons<Clause>::List clause_list_;
friend Elser If(const BoolExpr&, const ResultExpr&);
+ template <typename T>
+ friend Caser<T> Switch(const Arg<T>&);
DISALLOW_ASSIGN(Elser);
};
+// Switch begins a switch expression dispatched according to the
+// specified argument value.
+template <typename T>
+SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg);
+
+template <typename T>
+class SANDBOX_EXPORT Caser {
+ public:
+ Caser(const Caser<T>& caser) : arg_(caser.arg_), elser_(caser.elser_) {}
+ ~Caser() {}
+
+ // Case adds a single-value "case" clause to the switch.
+ Caser<T> Case(T value, ResultExpr result) const;
+
+ // Cases adds a multiple-value "case" clause to the switch.
+ // See also the SANDBOX_BPF_DSL_CASES macro below for a more idiomatic way
+ // of using this function.
+ Caser<T> Cases(const std::vector<T>& values, ResultExpr result) const;
+
+ // Terminate the switch with a "default" clause.
+ ResultExpr Default(ResultExpr result) const;
+
+ private:
+ Caser(const Arg<T>& arg, Elser elser) : arg_(arg), elser_(elser) {}
+
+ Arg<T> arg_;
+ Elser elser_;
+
+ template <typename U>
+ friend Caser<U> Switch(const Arg<U>&);
+ DISALLOW_ASSIGN(Caser);
+};
+
+// Recommended usage is to put
+// #define CASES SANDBOX_BPF_DSL_CASES
+// near the top of the .cc file (e.g., nearby any "using" statements), then
+// use like:
+// Switch(arg).CASES((3, 5, 7), result)...;
+#define SANDBOX_BPF_DSL_CASES(values, result) \
+ Cases(SANDBOX_BPF_DSL_CASES_HELPER values, result)
+
+// Helper macro to construct a std::vector from an initializer list.
+// TODO(mdempsky): Convert to use C++11 initializer lists instead.
+#define SANDBOX_BPF_DSL_CASES_HELPER(value, ...) \
+ ({ \
+ const __typeof__(value) bpf_dsl_cases_values[] = {value, __VA_ARGS__}; \
+ std::vector<__typeof__(value)>( \
+ bpf_dsl_cases_values, \
+ bpf_dsl_cases_values + arraysize(bpf_dsl_cases_values)); \
+ })
+
// =====================================================================
// Official API ends here.
// =====================================================================
@@ -261,6 +322,36 @@ BoolExpr Arg<T>::EqualTo(T val) const {
return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(val));
}
+template <typename T>
+SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg) {
+ return Caser<T>(arg, Elser(Cons<Elser::Clause>::List()));
+}
+
+template <typename T>
+Caser<T> Caser<T>::Case(T value, ResultExpr result) const {
+ return SANDBOX_BPF_DSL_CASES((value), result);
+}
+
+template <typename T>
+Caser<T> Caser<T>::Cases(const std::vector<T>& values,
+ ResultExpr result) const {
+ // Theoretically we could evaluate arg_ just once and emit a more efficient
+ // dispatch table, but for now we simply translate into an equivalent
+ // If/ElseIf/Else chain.
+
+ typedef typename std::vector<T>::const_iterator Iter;
+ BoolExpr test = BoolConst(false);
+ for (Iter i = values.begin(), end = values.end(); i != end; ++i) {
+ test = test || (arg_ == *i);
+ }
+ return Caser<T>(arg_, elser_.ElseIf(test, result));
+}
+
+template <typename T>
+ResultExpr Caser<T>::Default(ResultExpr result) const {
+ return elser_.Else(result);
+}
+
} // namespace bpf_dsl
} // namespace sandbox
« no previous file with comments | « no previous file | sandbox/linux/bpf_dsl/bpf_dsl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698