1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* 2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2015 Google Inc. 3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be 5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file. 6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifndef SkRecordPattern_DEFINED 9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define SkRecordPattern_DEFINED 10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRecord.h" 12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTLogic.h" 13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace SkRecords { 15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// First, some matchers. These match a single command in the SkRecord, 17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// and may hang onto some data from it. If so, you can get the data by calling .get(). 18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Matches a command of type T, and stores that command. 20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T> 21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass Is { 22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic: 23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot Is() : fPtr(nullptr) {} 24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot typedef T type; 26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot type* get() { return fPtr; } 27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool operator()(T* ptr) { 29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPtr = ptr; 30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename U> 34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool operator()(U*) { 35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPtr = nullptr; 36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate: 40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot type* fPtr; 41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Matches any command that draws, and stores its paint. 44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass IsDraw { 45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic: 46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot IsDraw() : fPaint(nullptr) {} 47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot typedef SkPaint type; 49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot type* get() { return fPaint; } 50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> 52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SK_WHEN((T::kTags & kDrawWithPaint_Tag) == kDrawWithPaint_Tag, bool) operator()(T* draw) { 53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPaint = AsPtr(draw->paint); 54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> 58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SK_WHEN((T::kTags & kDrawWithPaint_Tag) == kDraw_Tag, bool) operator()(T* draw) { 59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPaint = nullptr; 60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> 64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SK_WHEN(!(T::kTags & kDraw_Tag), bool) operator()(T* draw) { 65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPaint = nullptr; 66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate: 70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Abstracts away whether the paint is always part of the command or optional. 71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> static T* AsPtr(SkRecords::Optional<T>& x) { return x; } 72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> static T* AsPtr(T& x) { return &x; } 73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot type* fPaint; 75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Matches if Matcher doesn't. Stores nothing. 78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename Matcher> 79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct Not { 80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> 81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool operator()(T* ptr) { return !Matcher()(ptr); } 82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Matches if any of First or Rest... does. Stores nothing. 85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename First, typename... Rest> 86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct Or { 87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> 88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool operator()(T* ptr) { return First()(ptr) || Or<Rest...>()(ptr); } 89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename First> 91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct Or<First> { 92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> 93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool operator()(T* ptr) { return First()(ptr); } 94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Greedy is a special matcher that greedily matches Matcher 0 or more times. Stores nothing. 98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename Matcher> 99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct Greedy { 100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> 101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool operator()(T* ptr) { return Matcher()(ptr); } 102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Pattern matches each of its matchers in order. 105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// This is the main entry point to pattern matching, and so provides a couple of extra API bits: 107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// - search scans through the record to look for matches; 108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// - first, second, third, ... return the data stored by their respective matchers in the pattern. 109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename... Matchers> class Pattern; 111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <> class Pattern<> { 113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic: 114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Bottoms out recursion. Just return whatever i the front decided on. 115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int match(SkRecord*, int i) { return i; } 116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename First, typename... Rest> 119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass Pattern<First, Rest...> { 120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic: 121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // If this pattern matches the SkRecord starting from i, 122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // return the index just past the end of the pattern, otherwise return 0. 123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SK_ALWAYS_INLINE int match(SkRecord* record, int i) { 124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot i = this->matchFirst(&fFirst, record, i); 125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return i > 0 ? fRest.match(record, i) : 0; 126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Starting from *end, walk through the SkRecord to find the first span matching this pattern. 129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // If there is no such span, return false. If there is, return true and set [*begin, *end). 130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SK_ALWAYS_INLINE bool search(SkRecord* record, int* begin, int* end) { 131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (*begin = *end; *begin < record->count(); ++(*begin)) { 132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *end = this->match(record, *begin); 133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (*end != 0) { 134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // TODO: some sort of smart get<i>() 141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> T* first() { return fFirst.get(); } 142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> T* second() { return fRest.template first<T>(); } 143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> T* third() { return fRest.template second<T>(); } 144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> T* fourth() { return fRest.template third<T>(); } 145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate: 147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // If first isn't a Greedy, try to match at i once. 148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> 149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int matchFirst(T* first, SkRecord* record, int i) { 150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (i < record->count()) { 151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (record->mutate(i, *first)) { 152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return i+1; 153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return 0; 156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // If first is a Greedy, walk i until it doesn't match. 159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot template <typename T> 160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int matchFirst(Greedy<T>* first, SkRecord* record, int i) { 161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (i < record->count()) { 162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!record->mutate(i, *first)) { 163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return i; 164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot i++; 166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return 0; 168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot First fFirst; 171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot Pattern<Rest...> fRest; 172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} // namespace SkRecords 175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif//SkRecordPattern_DEFINED 177