mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Add simple_match
Add some python build scripts.
This commit is contained in:
@@ -454,6 +454,8 @@ foreach(TINYUSDZ_LIB_TARGET ${TINYUSDZ_LIBS})
|
||||
# PRIVATE ${PROJECT_SOURCE_DIR}/src/external/ryu/)
|
||||
target_include_directories(${TINYUSDZ_LIB_TARGET}
|
||||
PRIVATE ${PROJECT_SOURCE_DIR}/src/external/fast_float/include)
|
||||
target_include_directories(${TINYUSDZ_LIB_TARGET}
|
||||
PRIVATE ${PROJECT_SOURCE_DIR}/src/external/simple_match/include)
|
||||
|
||||
target_include_directories(
|
||||
${TINYUSDZ_LIB_TARGET} PRIVATE ${PROJECT_SOURCE_DIR}/src/external/jsonhpp/)
|
||||
@@ -542,8 +544,12 @@ if(TINYUSDZ_WITH_PYTHON AND (NOT TINYUSDZ_WITH_BLENDER_ADDON))
|
||||
nanobind_add_module(${BUILD_TARGET_PY} ${TINYUSDZ_PYTHON_BINDING_SOURCES})
|
||||
add_sanitizers(${BUILD_TARGET_PY})
|
||||
target_link_libraries(${BUILD_TARGET_PY} PRIVATE ${TINYUSDZ_TARGET_STATIC})
|
||||
|
||||
# strip "py" prefix
|
||||
set_target_properties(${BUILD_TARGET_PY} PROPERTIES OUTPUT_NAME "tinyusdz")
|
||||
|
||||
# copy python binding .so file to python/
|
||||
# For developer
|
||||
add_custom_command(
|
||||
TARGET ${BUILD_TARGET_PY}
|
||||
POST_BUILD
|
||||
@@ -552,6 +558,9 @@ if(TINYUSDZ_WITH_PYTHON AND (NOT TINYUSDZ_WITH_BLENDER_ADDON))
|
||||
COMMENT "copying python module file to python/"
|
||||
VERBATIM)
|
||||
|
||||
# For pypi packaging
|
||||
install(TARGETS ${BUILD_TARGET_PY} LIBRARY DESTINATION tinyusdz)
|
||||
|
||||
endif()
|
||||
|
||||
if(TINYUSDZ_WITH_TOOL_USDA_PARSER AND TINYUSDZ_WITH_MODULE_USDA_READER)
|
||||
|
||||
@@ -301,3 +301,4 @@ TinyUSDZ is licensed under MIT license.
|
||||
* ubench.h: Unlicense. https://github.com/sheredom/ubench.h
|
||||
* thelink2012/any : BSL-1.0 license. https://github.com/thelink2012/any
|
||||
* better-enums : BSD-2 license. https://aantron.github.io/better-enums/
|
||||
* simple_match : BSL-1.0 license. https://github.com/jbandela/simple_match
|
||||
|
||||
7
pyproject.toml
Normal file
7
pyproject.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=42", "wheel", "scikit-build", "cmake>=3.16", "ninja"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = [ "tests" ]
|
||||
@@ -1,5 +1,5 @@
|
||||
Python binding of tinyusdz.
|
||||
This folder is used for packaging Python binding of TinyUSDZ
|
||||
|
||||
Core part is deletegated to native module(pytinyusd)
|
||||
Core part is deletegated to native module(tinyusd)
|
||||
|
||||
W.I.P.
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
# based on https://stackoverflow.com/questions/42585210/extending-setuptools-extension-to-use-cmake-in-setup-py
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
from setuptools import setup, Extension
|
||||
from setuptools.command.build_ext import build_ext as build_ext_orig
|
||||
|
||||
|
||||
class CMakeExtension(Extension):
|
||||
|
||||
def __init__(self, name):
|
||||
# don't invoke the original build_ext for this special extension
|
||||
super().__init__(name, sources=[])
|
||||
|
||||
|
||||
class build_ext(build_ext_orig):
|
||||
|
||||
def run(self):
|
||||
for ext in self.extensions:
|
||||
self.build_cmake(ext)
|
||||
super().run()
|
||||
|
||||
def build_cmake(self, ext):
|
||||
cwd = pathlib.Path().absolute()
|
||||
print("cwd = ", cwd)
|
||||
|
||||
# these dirs will be created in build_py, so if you don't have
|
||||
# any python sources to bundle, the dirs will be missing
|
||||
build_temp = pathlib.Path(self.build_temp)
|
||||
build_temp.mkdir(parents=True, exist_ok=True)
|
||||
extdir = pathlib.Path(self.get_ext_fullpath(ext.name))
|
||||
extdir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
config = 'RelWithDebInfo'
|
||||
cmake_args = [
|
||||
'-S{}'.format(os.path.join(cwd, "..")),
|
||||
'-B{}'.format(build_temp),
|
||||
'-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + str(extdir.parent.absolute()),
|
||||
'-DCMAKE_BUILD_TYPE=' + config
|
||||
]
|
||||
|
||||
# example of build args
|
||||
build_args = [
|
||||
'--config', config,
|
||||
'--', '-j4'
|
||||
]
|
||||
|
||||
print("cmake_args = ", cmake_args)
|
||||
|
||||
#os.chdir(str(build_temp))
|
||||
self.spawn(['cmake'] + cmake_args)
|
||||
if not self.dry_run:
|
||||
self.spawn(['cmake', '--build', str(build_temp)] + build_args)
|
||||
# Troubleshooting: if fail on line above then delete all possible
|
||||
# temporary CMake files including "CMakeCache.txt" in top level dir.
|
||||
os.chdir(str(cwd))
|
||||
|
||||
|
||||
setup(
|
||||
name='pytinyusdz',
|
||||
version='0.8.0rc0',
|
||||
packages=['pytinyusdz'],
|
||||
long_description=open("../README.md", 'r').read(),
|
||||
ext_modules=[CMakeExtension('pytinyusdz')],
|
||||
license='MIT',
|
||||
cmdclass={
|
||||
'build_ext': build_ext,
|
||||
}
|
||||
)
|
||||
72
setup.py
Normal file
72
setup.py
Normal file
@@ -0,0 +1,72 @@
|
||||
# based on https://stackoverflow.com/questions/42585210/extending-setuptools-extension-to-use-cmake-in-setup-py
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
from skbuild import setup
|
||||
#from setuptools.command.build_ext import build_ext as build_ext_orig
|
||||
|
||||
|
||||
#class CMakeExtension(Extension):
|
||||
#
|
||||
# def __init__(self, name):
|
||||
# # don't invoke the original build_ext for this special extension
|
||||
# super().__init__(name, sources=[])
|
||||
#
|
||||
#
|
||||
#class build_ext(build_ext_orig):
|
||||
#
|
||||
# def run(self):
|
||||
# for ext in self.extensions:
|
||||
# self.build_cmake(ext)
|
||||
# super().run()
|
||||
#
|
||||
# def build_cmake(self, ext):
|
||||
# cwd = pathlib.Path().absolute()
|
||||
# print("cwd = ", cwd)
|
||||
#
|
||||
# # these dirs will be created in build_py, so if you don't have
|
||||
# # any python sources to bundle, the dirs will be missing
|
||||
# build_temp = pathlib.Path(self.build_temp)
|
||||
# build_temp.mkdir(parents=True, exist_ok=True)
|
||||
# extdir = pathlib.Path(self.get_ext_fullpath(ext.name))
|
||||
# extdir.mkdir(parents=True, exist_ok=True)
|
||||
#
|
||||
# config = 'RelWithDebInfo'
|
||||
# cmake_args = [
|
||||
# '-S{}'.format(os.path.join(cwd, "..")),
|
||||
# '-B{}'.format(build_temp),
|
||||
# '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + str(extdir.parent.absolute()),
|
||||
# '-DCMAKE_BUILD_TYPE=' + config
|
||||
# ]
|
||||
#
|
||||
# # example of build args
|
||||
# build_args = [
|
||||
# '--config', config,
|
||||
# '--', '-j4'
|
||||
# ]
|
||||
#
|
||||
# print("cmake_args = ", cmake_args)
|
||||
#
|
||||
# #os.chdir(str(build_temp))
|
||||
# self.spawn(['cmake'] + cmake_args)
|
||||
# if not self.dry_run:
|
||||
# self.spawn(['cmake', '--build', str(build_temp)] + build_args)
|
||||
# # Troubleshooting: if fail on line above then delete all possible
|
||||
# # temporary CMake files including "CMakeCache.txt" in top level dir.
|
||||
# os.chdir(str(cwd))
|
||||
|
||||
|
||||
setup(
|
||||
name='tinyusdz',
|
||||
version='0.8.0rc0',
|
||||
author='Light Transport Entertainment Inc.',
|
||||
author_email='lighttransport.eth@mail3.me',
|
||||
packages_dir=['python'], # Use `python` folder
|
||||
cmake_args=['-DTINYUSDZ_WITH_PYTHON=1'],
|
||||
long_description=open("./README.md", 'r').read(),
|
||||
#ext_modules=[CMakeExtension('pytinyusdz')],
|
||||
license='MIT',
|
||||
#cmdclass={
|
||||
# 'build_ext': build_ext,
|
||||
#}
|
||||
)
|
||||
23
src/external/simple_match/LICENSE_1_0.txt
vendored
Normal file
23
src/external/simple_match/LICENSE_1_0.txt
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
371
src/external/simple_match/README.md
vendored
Normal file
371
src/external/simple_match/README.md
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
# Simple, Extensible C++ Pattern Matching Library
|
||||
|
||||
I have recently been looking at Haskell and Rust. One of the things I wanted in C++ from those languages is pattern matching.
|
||||
|
||||
Here is an example from the Rustlang Book (http://static.rust-lang.org/doc/master/book/match.html)
|
||||
|
||||
```rust
|
||||
match x {
|
||||
1 => println!("one"),
|
||||
2 => println!("two"),
|
||||
3 => println!("three"),
|
||||
4 => println!("four"),
|
||||
5 => println!("five"),
|
||||
_ => println!("something else"),
|
||||
}
|
||||
```
|
||||
There is currently a C++ Library Mach7 that does pattern matching (https://github.com/solodon4/Mach7), however it is big, complicated, and uses a lot of macros. I wanted to see if I could use C++14 to write a simple implementation without macros.
|
||||
|
||||
This library is the result of that effort. If you are familiar with C++14 especially variadic templates, forwarding, and tuples, this library and implementation should be easy for you to understand and extend.
|
||||
|
||||
## Usage
|
||||
You will need a C++14 compiler. I have used the latest Visual C++ 2015 CTP, GCC 4.9.2, and Clang 3.5 to test this library.
|
||||
|
||||
The library consists of 2 headers. `simple_match.hpp` which is the core of the library, and `some_none.hpp` which contains code that lets you match on raw pointers, and unique_ptr, and shared_ptr.
|
||||
|
||||
Here is a simple excerpt. Assume you have included simple_match.hpp
|
||||
|
||||
```cpp
|
||||
using namespace simple_match;
|
||||
using namespace simple_match::placeholders;
|
||||
|
||||
int x = 0;
|
||||
|
||||
while (true) {
|
||||
std::cin >> x;
|
||||
match(x,
|
||||
1, []() {std::cout << "The answer is one\n"; },
|
||||
2, []() {std::cout << "The answer is two\n"; },
|
||||
_x < 10, [](auto&& a) {std::cout << "The answer " << a << " is less than 10\n"; },
|
||||
10 < _x < 20, [](auto&& a) {std::cout << "The answer " << a << " is between 10 and 20 exclusive\n"; },
|
||||
_, []() {std::cout << "Did not match\n"; }
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Example Files
|
||||
There are 2 files under the test directory: `test.cpp` and `cppcon-matching.cpp`. `test.cpp` contains just some simple tests of matching. `cppcon-matching.cpp`contains the example from Mach7 that was presented at cppcon.
|
||||
|
||||
## Extending
|
||||
There are 2 points of customization provided in namespace `simple_matcher::customization`. They are
|
||||
```cpp
|
||||
template<class T, class U>
|
||||
struct matcher;
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```cpp
|
||||
template<class Type>
|
||||
struct tuple_adapter;
|
||||
```
|
||||
## License
|
||||
Licensed under the Boost Software License.
|
||||
|
||||
## Tutorial
|
||||
|
||||
We are going to assume you have the following at the top of your file
|
||||
|
||||
```cpp
|
||||
#include "simple_match/simple_match.hpp"
|
||||
|
||||
|
||||
using namespace simple_match;
|
||||
using namespace simple_match::placeholders;
|
||||
```
|
||||
|
||||
Here is how to match exactly
|
||||
|
||||
```cpp
|
||||
int i = 0;
|
||||
match(i,
|
||||
1, [](){std::cout << "The answer is one";}
|
||||
2, [](){std::cout << "The answer is two";}
|
||||
otherwise, [](){std::cout << "Did not match"}
|
||||
);
|
||||
```
|
||||
The match function will try matching from top to bottom and run the lamba corresponding to the first successful match. `otherwise` always matches, and therefore you should have it at the end. If you find `otherwise` too long, you can also use `_`. It is located in the namespace `simple_match::placeholders`
|
||||
|
||||
Match also works for strings.
|
||||
```
|
||||
std::string s = "";
|
||||
|
||||
match(s,
|
||||
"Hello", [](){ std::cout << " You said hello\n";},
|
||||
_, [](){std::cout << "I do not know what you said\n";} // _ is the same as otherwise
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
|
||||
You can even return values from a match
|
||||
|
||||
```cpp
|
||||
char digit = '0';
|
||||
|
||||
int value = match(digit,
|
||||
'0', [](){return 0;},
|
||||
'1', [](){return 1;},
|
||||
'2', [](){return 2;},
|
||||
'3', [](){return 3;},
|
||||
'4', [](){return 4;},
|
||||
'5', [](){return 5;},
|
||||
// and so on
|
||||
);
|
||||
```
|
||||
|
||||
We can also do comparisons, and ranges. To do so use `_x` from the `simple_match::placeholders` namespace.
|
||||
|
||||
```cpp
|
||||
int i = 0;
|
||||
match(i,
|
||||
_x < 0, [](int x){std::cout << x << " is a negative number\n";},
|
||||
1 < _x < 10, [](int z){std::cout << z << " is between 1 and 10\n"},
|
||||
_x, [](int x){std::cout << x << " is the value\n";}
|
||||
);
|
||||
|
||||
```
|
||||
There are a some items of interest in the above example. When `_x` is used, it passes its value to the lambda. If `_x` is used without any comparison, it will pass the value to the lambda. Also, because of the way it is overloaded, it is very easy to make ranges using the `<` or `<=` operator as seen in the match above.
|
||||
|
||||
### Tuples
|
||||
|
||||
Now we can even have more fun! Let's represent a 2d point as a tuple.
|
||||
|
||||
```cpp
|
||||
std::tuple<int,int> p(0,0);
|
||||
|
||||
match(p,
|
||||
ds(0,0), [](){std::cout << "Point is at the origin";},
|
||||
ds(0,_), [](){std::cout << "Point is on the horizontal axis";},
|
||||
ds(_,0), [](){std::cout << "Point is on the vertical axis";}.
|
||||
ds(_x < 10,_), [](int x){std::cout << x << " is less than 10";},
|
||||
ds(_x,_x), [](int x, int y){ std::cout << x << "," << y << " Is not on an axis";}
|
||||
);
|
||||
```
|
||||
|
||||
`ds` stands for de-structure and splits a tuple into its parts. Notice you can use the same expressions as you could without tuples. As before `_x` results in a value being passed to the lambda. `_` matches anything and ignores it, so no corresponding variable is passed to the lambda.
|
||||
|
||||
We can actually use `ds` to deconstruct our own `struct`s and `class`es .
|
||||
First we have to specialize `simple_match::customization::tuple_adapter` for our type.
|
||||
|
||||
```cpp
|
||||
struct point {
|
||||
int x;
|
||||
int y;
|
||||
point(int x_,int y_):x(x_),y(y_){}
|
||||
};
|
||||
|
||||
// Adapting point to be used with ds
|
||||
namespace simple_match {
|
||||
namespace customization {
|
||||
template<>
|
||||
struct tuple_adapter<point>{
|
||||
|
||||
enum { tuple_len = 2 };
|
||||
|
||||
template<size_t I, class T>
|
||||
static decltype(auto) get(T&& t) {
|
||||
return std::get<I>(std::tie(t.x,t.y));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then we can use `ds` like we did with a tuple.
|
||||
|
||||
```cpp
|
||||
point p{0,0};
|
||||
|
||||
match(p,
|
||||
ds(0,0), [](){std::cout << "Point is at the origin";},
|
||||
ds(0,_), [](){std::cout << "Point is on the horizontal axis";},
|
||||
ds(_,0), [](){std::cout << "Point is on the vertical axis";}.
|
||||
ds(_x < 10,_), [](int x){std::cout << x << " is less than 10";},
|
||||
ds(_x,_x), [](int x, int y){ std::cout << x << "," << y << " Is not on an axis";}
|
||||
);
|
||||
```
|
||||
|
||||
### Pointers as option types
|
||||
Sometimes we have pointer that we want to get a value safely out of. To do this we can use `some` and `none` . To do this we have to include `simple_match/some_none.hpp`
|
||||
|
||||
Let us use the same `point` as before
|
||||
|
||||
```cpp
|
||||
point* pp = new point(0,0);
|
||||
|
||||
match(pp,
|
||||
some(), [](point& p){std::cout << p.x << " is the x-value";}
|
||||
none(), [](){std::cout << "Null pointer\n";}
|
||||
);
|
||||
```
|
||||
|
||||
Notice how `some()` converted the pointer to a reference and passed it to us.
|
||||
|
||||
Now, that is now how we should allocate memory with a naked new. We would probably use a `std::unique_ptr`. `some` has built in support for `unique_ptr` and `shared_ptr`. So we can write it like this.
|
||||
|
||||
```cpp
|
||||
auto pp = std::make_unique<point>(0,0);
|
||||
|
||||
match(pp,
|
||||
some(), [](point& p){std::cout << p.x << " is the x-value";}
|
||||
none(), [](){std::cout << "Null pointer\n";}
|
||||
);
|
||||
```
|
||||
Notice, how our match code did not change.
|
||||
|
||||
We can do better because `some` composes. Since we specialized `tuple_adapter` we can use `ds` with `point`.
|
||||
|
||||
```cpp
|
||||
auto pp = std::make_unique<point>(0,0);
|
||||
|
||||
match(pp,
|
||||
some(ds(0,0)), [](){std::cout << "Point is at the origin";},
|
||||
some(ds(0,_)), [](){std::cout << "Point is on the horizontal axis";},
|
||||
some(ds(_,0)), [](){std::cout << "Point is on the vertical axis";}.
|
||||
some(ds(_x < 10,_)), [](int x){std::cout << x << " is less than 10";},
|
||||
some(ds(_x,_x)), [](int x, int y){ std::cout << x << "," << y << " Is not on an axis";},
|
||||
none(), [](){std::cout << "Null pointer";}
|
||||
);
|
||||
```
|
||||
Notice how `some` and `ds` compose. If we wanted to to, we could have pointers in tuples, and tuples in pointers and it would just work.
|
||||
|
||||
`some` can also use RTTI to do downcasting.
|
||||
|
||||
Here is an example. We will now make `point` a base class and have point2d, and point3d as subclasses, and adapt them.
|
||||
|
||||
```cpp
|
||||
struct point{
|
||||
virtual ~point(){}
|
||||
};
|
||||
|
||||
struct point2d:point{
|
||||
int x;
|
||||
int y;
|
||||
point2d(int x_,int y_):x(x_),y(y_){}
|
||||
};
|
||||
|
||||
struct point3d:point{
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
point3d(int x_,int y_, int z_):x(x_),y(y_),z(z_){}
|
||||
};
|
||||
|
||||
// Adapting point2d and point3d to be used with ds
|
||||
namespace simple_match {
|
||||
namespace customization {
|
||||
template<>
|
||||
struct tuple_adapter<point2d>{
|
||||
|
||||
enum { tuple_len = 2 };
|
||||
|
||||
template<size_t I, class T>
|
||||
static decltype(auto) get(T&& t) {
|
||||
return std::get<I>(std::tie(t.x,t.y));
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct tuple_adapter<point3d>{
|
||||
|
||||
enum { tuple_len = 3 };
|
||||
|
||||
template<size_t I, class T>
|
||||
static decltype(auto) get(T&& t) {
|
||||
return std::get<I>(std::tie(t.x,t.y,t.z));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then we can use it like this
|
||||
|
||||
```cpp
|
||||
std::unique_ptr<point> pp(new point2d(0,0));
|
||||
|
||||
match(pp,
|
||||
some<point2d>(ds(_x,_x)), [](int x, int y){std::cout << x << "," << y;},
|
||||
some<point3d>(ds(_x,_x,_x)), [](int x, int y, int z){std::cout << x << "," << y << "," << z;},
|
||||
some(), [](point& p){std::cout << "Unknown point type\n"},
|
||||
none(), [](){std::cout << "Null pointer\n"}
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Notice how we can safely downcast, and use `ds` to destructure the `point`. Everything composes nicely.
|
||||
|
||||
# Implementation Details
|
||||
|
||||
simple_match actually was easier to implement than I thought it would be. I used the apply sample implementation from http://isocpp.org/files/papers/N3915.pdf to call a function with a tuple as arguments.
|
||||
|
||||
Here is the core of the implementation
|
||||
|
||||
```cpp
|
||||
template<class T, class U>
|
||||
bool match_check(T&& t, U&& u) {
|
||||
using namespace customization;
|
||||
using m = matcher<std::decay_t<T>, std::decay_t<U>>;
|
||||
return m::check(std::forward<T>(t), std::forward<U>(u));
|
||||
}
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
auto match_get(T&& t, U&& u) {
|
||||
using namespace customization;
|
||||
using m = matcher<std::decay_t<T>, std::decay_t<U>>;
|
||||
return m::get(std::forward<T>(t), std::forward<U>(u));
|
||||
}
|
||||
|
||||
template<class T, class A1, class F1>
|
||||
auto match(T&& t, A1&& a, F1&& f) {
|
||||
if (match_check(std::forward<T>(t), std::forward<A1>(a))) {
|
||||
return detail::apply(f, match_get(std::forward<T>(t), std::forward<A1>(a)));
|
||||
}
|
||||
else {
|
||||
throw std::logic_error("No match");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T, class A1, class F1, class A2, class F2, class... Args>
|
||||
auto match(T&& t, A1&& a, F1&& f, A2&& a2, F2&& f2, Args&&... args) {
|
||||
if (match_check(t, a)) {
|
||||
return detail::apply(f, match_get(std::forward<T>(t), std::forward<A1>(a)));
|
||||
}
|
||||
else {
|
||||
return match(t, std::forward<A2>(a2), std::forward<F2>(f2), std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`match` is a variadic function that takes the value to be matched, and then parameters for the match criteria, and lambda to be executed if the criteria succeeds. It goes through calling `match_check` until it returns true. Then it calls `match_get` to get a tuple of the values that need to be forwarded to the lambda, and uses apply to call the lambda.
|
||||
|
||||
The match types are implemented by specializing `simple_match::customization::matcher`
|
||||
```cpp
|
||||
namespace customization {
|
||||
template<class T, class U>
|
||||
struct matcher;
|
||||
}
|
||||
```
|
||||
|
||||
For an example, here is how the matcher that matches to values is implemented. Note, that it does not pass any values to the lambda and so returns an empty tuple.
|
||||
|
||||
```cpp
|
||||
// Match same type
|
||||
template<class T>
|
||||
struct matcher<T, T> {
|
||||
static bool check(const T& t, const T& v) {
|
||||
return t == v;
|
||||
}
|
||||
static auto get(const T&, const T&) {
|
||||
return std::tie();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
I hope you enjoy using this code, as much as I have enjoyed writing it. Please give me any feedback you may have.
|
||||
|
||||
-- John R. Bandela, MD
|
||||
|
||||
> Written with [StackEdit](https://stackedit.io/).
|
||||
369
src/external/simple_match/include/simple_match/implementation/some_none.hpp
vendored
Normal file
369
src/external/simple_match/include/simple_match/implementation/some_none.hpp
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
// Copyright 2015 John R. Bandela
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#pragma once
|
||||
#ifndef SIMPLE_MATCH_SOME_NONE_HPP_JRB_2015_03_21
|
||||
#define SIMPLE_MATCH_SOME_NONE_HPP_JRB_2015_03_21
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace simple_match {
|
||||
|
||||
namespace customization {
|
||||
|
||||
template<class Type>
|
||||
struct pointer_getter {};
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T, class C>
|
||||
struct cv_helper_imp;
|
||||
|
||||
template<class T, class C>
|
||||
struct cv_helper_imp<T*, C> {
|
||||
using type = std::add_pointer_t<C>;
|
||||
};
|
||||
|
||||
template<class T, class C>
|
||||
struct cv_helper_imp<const T*, C> {
|
||||
using type = std::add_pointer_t<std::add_const_t<C>>;
|
||||
};
|
||||
|
||||
template<class T, class C>
|
||||
struct cv_helper_imp<volatile T*, C> {
|
||||
using type = std::add_pointer_t<std::add_volatile_t<C>>;
|
||||
};
|
||||
|
||||
template<class T, class C>
|
||||
struct cv_helper_imp<const volatile T*, C> {
|
||||
using type = std::add_pointer_t<std::add_cv_t<C>>;
|
||||
};
|
||||
|
||||
}
|
||||
namespace utils {
|
||||
template<class T, class C>
|
||||
using cv_helper = typename detail::cv_helper_imp<T, C>::type;
|
||||
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
|
||||
|
||||
template<class Class, class Matcher>
|
||||
struct some_t{
|
||||
Matcher m_;
|
||||
|
||||
template<class T>
|
||||
bool check(T&& t) {
|
||||
auto ptr = customization::pointer_getter<std::decay_t<T>>::template get_pointer<Class>(std::forward<T>(t));
|
||||
if (!ptr) {
|
||||
return false;
|
||||
}
|
||||
return match_check(*ptr, m_);
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto get(T&& t) {
|
||||
auto ptr = customization::pointer_getter<std::decay_t<T>>::template get_pointer<Class>(std::forward<T>(t));
|
||||
return match_get(*ptr, m_);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<class Matcher>
|
||||
struct some_t<void,Matcher> {
|
||||
Matcher m_;
|
||||
|
||||
template<class T>
|
||||
bool check(T&& t) {
|
||||
// If you get an error here, this means that some() without a type is not supported
|
||||
// Examples of this are variants and boost::any
|
||||
auto ptr = customization::pointer_getter<std::decay_t<T>>::get_pointer_no_cast(std::forward<T>(t));
|
||||
if (!ptr) {
|
||||
return false;
|
||||
}
|
||||
return match_check(*ptr, m_);
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto get(T&& t) {
|
||||
auto ptr = (customization::pointer_getter<std::decay_t<T>>::get_pointer_no_cast(std::forward<T>(t)));
|
||||
return match_get(*ptr, m_);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<class Class>
|
||||
struct some_t<Class,void> {
|
||||
|
||||
template<class T>
|
||||
bool check(T&& t) {
|
||||
auto ptr = customization::pointer_getter<std::decay_t<T>>::template get_pointer<Class>(std::forward<T>(t));
|
||||
if (!ptr) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto get(T&& t) {
|
||||
auto ptr = customization::pointer_getter<std::decay_t<T>>::template get_pointer<Class>(std::forward<T>(t));
|
||||
return std::tie(*ptr);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<>
|
||||
struct some_t<void, void> {
|
||||
|
||||
template<class T>
|
||||
bool check(T&& t) {
|
||||
// If you get an error here, this means that some() without a type is not supported
|
||||
// Examples of this are variants and boost::any
|
||||
auto ptr = customization::pointer_getter<std::decay_t<T>>::get_pointer_no_cast(std::forward<T>(t));
|
||||
if (!ptr) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto get(T&& t) {
|
||||
auto ptr = customization::pointer_getter<std::decay_t<T>>::get_pointer_no_cast(std::forward<T>(t));
|
||||
return std::tie(*ptr);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct none_t{
|
||||
template<class T>
|
||||
bool check(T&& t) {
|
||||
// If you get an error here, this means that none() is not supported
|
||||
// Example is boost::variant which has a never empty guarantee
|
||||
return customization::pointer_getter<std::decay_t<T>>::is_null(std::forward<T>(t));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto get(T&&) {
|
||||
return std::tie();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
namespace customization {
|
||||
|
||||
template<class Type, class Class, class Matcher>
|
||||
struct matcher<Type,detail::some_t<Class,Matcher>> {
|
||||
template<class T, class U>
|
||||
static bool check(T&& t, U&& u) {
|
||||
return u.check(std::forward<T>(t));
|
||||
}
|
||||
template<class T, class U>
|
||||
static auto get(T&& t, U&& u) {
|
||||
return u.get(std::forward<T>(t));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
struct matcher<Type,detail::none_t> {
|
||||
template<class T, class U>
|
||||
static bool check(T&& t, U&& u) {
|
||||
return u.check(std::forward<T>(t));
|
||||
}
|
||||
template<class T, class U>
|
||||
static auto get(T&& t, U&& u) {
|
||||
return u.get(std::forward<T>(t));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
namespace customization {
|
||||
template<class Type>
|
||||
struct pointer_getter<Type*> {
|
||||
template<class To>
|
||||
static auto get_pointer(Type* t) {
|
||||
return dynamic_cast<utils::cv_helper<decltype(t),To>>(t);
|
||||
}
|
||||
static auto get_pointer_no_cast(Type* t) {
|
||||
return t;
|
||||
}
|
||||
static auto is_null(Type* t) {
|
||||
return !t;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class Type>
|
||||
struct pointer_getter<std::shared_ptr<Type>> {
|
||||
|
||||
template<class To, class T>
|
||||
static auto get_pointer(T&& t) {
|
||||
return dynamic_cast<utils::cv_helper<decltype(t.get()),To>>(t.get());
|
||||
}
|
||||
template<class T>
|
||||
static auto get_pointer_no_cast(T&& t) {
|
||||
return t.get();
|
||||
}
|
||||
template<class T>
|
||||
static auto is_null(T&& t) {
|
||||
return !t;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Type, class D>
|
||||
struct pointer_getter<std::unique_ptr<Type, D>> {
|
||||
template<class To, class T>
|
||||
static auto get_pointer(T&& t) {
|
||||
return dynamic_cast<utils::cv_helper<decltype(t.get()),To>>(t.get());
|
||||
}
|
||||
template<class T>
|
||||
static auto get_pointer_no_cast(T&& t) {
|
||||
return t.get();
|
||||
}
|
||||
template<class T>
|
||||
static auto is_null(T&& t) {
|
||||
return !t;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline detail::none_t none() { return detail::none_t{}; }
|
||||
|
||||
inline detail::some_t<void, void> some() { return detail::some_t<void, void>{}; }
|
||||
|
||||
// Make Matcher... a variadic template so it is a worse match than some<T>(T())
|
||||
template<class... Matcher>
|
||||
detail::some_t<void, Matcher...> some(Matcher&&... m) { return detail::some_t<void, Matcher...> { std::forward<Matcher>(m)... }; }
|
||||
|
||||
template<class Class, class Matcher>
|
||||
detail::some_t<Class, Matcher> some(Matcher&& m) {
|
||||
return detail::some_t<Class, Matcher> { std::forward<Matcher>(m) };
|
||||
}
|
||||
template<class Class>
|
||||
detail::some_t<Class, void> some() {
|
||||
return detail::some_t<Class, void>{ };
|
||||
}
|
||||
|
||||
|
||||
// exhaustiveness
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T, class Tuple>
|
||||
struct type_in_tuple {
|
||||
static const bool value = false;
|
||||
};
|
||||
template<class T, class First, class... Rest>
|
||||
struct type_in_tuple<T, std::tuple<First, Rest...>> {
|
||||
static const bool value = type_in_tuple<T, std::tuple<Rest...>>::value;
|
||||
};
|
||||
template<class T, class... Rest>
|
||||
struct type_in_tuple<T, std::tuple<T, Rest...>> {
|
||||
static const bool value = true;
|
||||
};
|
||||
template<class T>
|
||||
struct type_in_tuple<T, std::tuple<>> {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<class ArgTypes>
|
||||
struct has_otherwise {
|
||||
static const bool value = type_in_tuple<otherwise_t, ArgTypes>::value;
|
||||
};
|
||||
|
||||
template<bool, class ArgTypes,class... RequiredTypes>
|
||||
struct some_exhaustiveness_helper {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<class Tuple>
|
||||
struct get_some_classes {};
|
||||
|
||||
template<>
|
||||
struct get_some_classes<std::tuple<>> {
|
||||
using type = std::tuple<>;
|
||||
};
|
||||
|
||||
template<class First, class...Rest>
|
||||
struct get_some_classes<std::tuple<First, Rest...>> {
|
||||
using type = typename get_some_classes<std::tuple<Rest...>>::type;
|
||||
|
||||
};
|
||||
template<class Class, class Matcher, class...Rest>
|
||||
struct get_some_classes<std::tuple<some_t<Class,Matcher>, Rest...>> {
|
||||
using type = cat_tuple_t<std::tuple<Class>, typename get_some_classes<std::tuple<Rest...>>::type>;
|
||||
|
||||
};
|
||||
|
||||
template<class SomeClasses, class... Required>
|
||||
struct all_in {};
|
||||
|
||||
template<bool b, class Type>
|
||||
struct not_in_match_asserter {
|
||||
static const bool value = b;
|
||||
static_assert(value, "This type is not in the match");
|
||||
};
|
||||
|
||||
template<class SomeClasses, class First, class... Rest>
|
||||
struct all_in<SomeClasses,First,Rest...> {
|
||||
static const bool myvalue = type_in_tuple<First, SomeClasses>::value;
|
||||
static const bool value = not_in_match_asserter<myvalue, First>::value&& all_in<SomeClasses, Rest...>::value;
|
||||
|
||||
};
|
||||
template<class SomeClasses, class First>
|
||||
struct all_in<SomeClasses,First> {
|
||||
static const bool myvalue = type_in_tuple<First, SomeClasses>::value;
|
||||
// static_assert(type_in_tuple<First, SomeClasses>::value, "This classes is not in the match");
|
||||
static const bool value = not_in_match_asserter<myvalue, First>::value;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<class ArgTypes, class... RequiredTypes>
|
||||
struct some_exhaustiveness_helper<false,ArgTypes,RequiredTypes...> {
|
||||
using some_classes = typename get_some_classes<ArgTypes>::type;
|
||||
using a = all_in<some_classes, RequiredTypes...>;
|
||||
static const bool value = a::value;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<class... Types>
|
||||
struct some_exhaustiveness {
|
||||
template<class ArgTypes>
|
||||
struct type {
|
||||
static const bool v = detail::has_otherwise<ArgTypes>::value;
|
||||
using seh = detail::some_exhaustiveness_helper<v, ArgTypes, Types...>;
|
||||
static const bool value = seh::value;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
404
src/external/simple_match/include/simple_match/simple_match.hpp
vendored
Normal file
404
src/external/simple_match/include/simple_match/simple_match.hpp
vendored
Normal file
@@ -0,0 +1,404 @@
|
||||
// Copyright 2015 John R. Bandela
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#pragma once
|
||||
#ifndef SIMPLE_MATCH_HPP_JRB_2015_03_21
|
||||
#define SIMPLE_MATCH_HPP_JRB_2015_03_21
|
||||
|
||||
//#include <stdexcept>
|
||||
#include <tuple>
|
||||
|
||||
namespace simple_match {
|
||||
using std::size_t;
|
||||
namespace customization {
|
||||
template<class T, class U>
|
||||
struct matcher;
|
||||
|
||||
}
|
||||
|
||||
// Apply adapted from http://isocpp.org/files/papers/N3915.pdf
|
||||
namespace detail {
|
||||
template <typename F, typename Tuple, size_t... I>
|
||||
decltype(auto) apply_impl(F&& f, Tuple&& t, std::integer_sequence<size_t, I...>) {
|
||||
using namespace std;
|
||||
return std::forward<F>(f)(get<I>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
template <typename F, typename Tuple>
|
||||
decltype(auto) apply(F&& f, Tuple&& t) {
|
||||
using namespace std;
|
||||
using Indices = make_index_sequence<tuple_size<decay_t<Tuple>>::value>;
|
||||
return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices{});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// exhaustiveness
|
||||
namespace detail {
|
||||
template<class TA, class TB>
|
||||
struct cat_tuple {};
|
||||
|
||||
template<class... A, class... B>
|
||||
struct cat_tuple<std::tuple<A...>,std::tuple<B...>> {
|
||||
using type = std::tuple<A..., B...>;
|
||||
|
||||
};
|
||||
|
||||
template<class TA, class TB>
|
||||
using cat_tuple_t = typename cat_tuple<TA, TB>::type;
|
||||
|
||||
template<class... A>
|
||||
struct arg_types {
|
||||
|
||||
};
|
||||
|
||||
template<class A, class F>
|
||||
struct arg_types<A,F> {
|
||||
using type = std::tuple<std::decay_t<A>>;
|
||||
};
|
||||
|
||||
|
||||
template<class A1, class F1, class A2, class F2, class... Args>
|
||||
struct arg_types<A1, F1, A2, F2, Args...>{
|
||||
using type = cat_tuple_t<std::tuple<std::decay_t<A1>, std::decay_t<A2>>, typename arg_types<Args...>::type>;
|
||||
|
||||
};
|
||||
|
||||
template<>
|
||||
struct arg_types<>{
|
||||
using type = std::tuple<>;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
struct empty_exhaustiveness {
|
||||
template<class ArgTypes>
|
||||
struct type{
|
||||
static const bool value = true;
|
||||
};
|
||||
};
|
||||
namespace customization {
|
||||
|
||||
template<class T>
|
||||
struct exhaustiveness_checker {
|
||||
using type = empty_exhaustiveness;
|
||||
};
|
||||
}
|
||||
|
||||
// end exhaustiveness
|
||||
|
||||
template<class T, class U>
|
||||
bool match_check(T&& t, U&& u) {
|
||||
using namespace customization;
|
||||
using m = matcher<std::decay_t<T>, std::decay_t<U>>;
|
||||
return m::check(std::forward<T>(t), std::forward<U>(u));
|
||||
}
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
auto match_get(T&& t, U&& u) {
|
||||
using namespace customization;
|
||||
using m = matcher<std::decay_t<T>, std::decay_t<U>>;
|
||||
return m::get(std::forward<T>(t), std::forward<U>(u));
|
||||
}
|
||||
|
||||
|
||||
//struct no_match :std::logic_error {
|
||||
// no_match() :logic_error{ "simple_match did not match" } {}
|
||||
//};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T, class A1, class F1>
|
||||
auto match_helper(T&& t, A1&& a, F1&& f) {
|
||||
if (match_check(std::forward<T>(t), std::forward<A1>(a))) {
|
||||
return detail::apply(f, match_get(std::forward<T>(t), std::forward<A1>(a)));
|
||||
}
|
||||
else {
|
||||
//throw no_match{};
|
||||
// tinyusdz: todo: report an error in another way.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T, class A1, class F1, class A2, class F2, class... Args>
|
||||
auto match_helper(T&& t, A1&& a, F1&& f, A2&& a2, F2&& f2, Args&&... args) {
|
||||
if (match_check(t, a)) {
|
||||
return detail::apply(f, match_get(std::forward<T>(t), std::forward<A1>(a)));
|
||||
}
|
||||
else {
|
||||
return match_helper(t, std::forward<A2>(a2), std::forward<F2>(f2), std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<class T, class... Args>
|
||||
auto match(T&& t, Args&&... a) {
|
||||
using atypes = typename detail::arg_types<Args...>::type;
|
||||
using ec = typename customization::exhaustiveness_checker<std::decay_t<T>>::type;
|
||||
using ctypes = typename ec::template type<atypes>;
|
||||
static_assert(ctypes::value, "Not all types are tested for in match");
|
||||
return detail::match_helper(std::forward<T>(t), std::forward<Args>(a)...);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct otherwise_t {};
|
||||
|
||||
namespace placeholders {
|
||||
const otherwise_t otherwise{};
|
||||
const otherwise_t _{};
|
||||
}
|
||||
|
||||
namespace customization {
|
||||
|
||||
// Match same type
|
||||
template<class T>
|
||||
struct matcher<T, T> {
|
||||
static bool check(const T& t, const T& v) {
|
||||
return t == v;
|
||||
}
|
||||
static auto get(const T&, const T&) {
|
||||
return std::tie();
|
||||
}
|
||||
|
||||
};
|
||||
// Match string literals
|
||||
template<class T>
|
||||
struct matcher<T, const char*> {
|
||||
static bool check(const T& t, const char* str) {
|
||||
return t == str;
|
||||
}
|
||||
static auto get(const T&, const T&) {
|
||||
return std::tie();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Match otherwise
|
||||
template<class Type>
|
||||
struct matcher<Type, otherwise_t> {
|
||||
template<class T>
|
||||
static bool check(T&&, otherwise_t) {
|
||||
return true;
|
||||
}
|
||||
template<class T>
|
||||
static auto get(T&&, otherwise_t) {
|
||||
return std::tie();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
template<class F>
|
||||
struct matcher_predicate {
|
||||
F f_;
|
||||
};
|
||||
|
||||
template<class F>
|
||||
matcher_predicate<F> make_matcher_predicate(F&& f) {
|
||||
return matcher_predicate<F>{std::forward<F>(f)};
|
||||
}
|
||||
|
||||
|
||||
namespace customization {
|
||||
|
||||
|
||||
template<class Type, class F>
|
||||
struct matcher<Type, matcher_predicate<F>> {
|
||||
template<class T, class U>
|
||||
static bool check(T&& t, U&& u) {
|
||||
return u.f_(std::forward<T>(t));
|
||||
}
|
||||
template<class T, class U>
|
||||
static auto get(T&& t, U&&) {
|
||||
return std::tie(std::forward<T>(t));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace placeholders {
|
||||
const auto _u = make_matcher_predicate([](auto&&) {return true; });
|
||||
const auto _v = make_matcher_predicate([](auto&&) {return true; });
|
||||
const auto _w = make_matcher_predicate([](auto&&) {return true; });
|
||||
const auto _x = make_matcher_predicate([](auto&&) {return true; });
|
||||
const auto _y = make_matcher_predicate([](auto&&) {return true; });
|
||||
const auto _z = make_matcher_predicate([](auto&&) {return true; });
|
||||
|
||||
// relational operators
|
||||
template<class F, class T>
|
||||
auto operator==(const matcher_predicate<F>& m, const T& t) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x == t; });
|
||||
}
|
||||
|
||||
template<class F, class T>
|
||||
auto operator!=(const matcher_predicate<F>& m, const T& t) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x != t; });
|
||||
}
|
||||
|
||||
template<class F, class T>
|
||||
auto operator<=(const matcher_predicate<F>& m, const T& t) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x <= t; });
|
||||
}
|
||||
template<class F, class T>
|
||||
auto operator>=(const matcher_predicate<F>& m, const T& t) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x >= t; });
|
||||
}
|
||||
template<class F, class T>
|
||||
auto operator<(const matcher_predicate<F>& m, const T& t) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x < t; });
|
||||
}
|
||||
template<class F, class T>
|
||||
auto operator>(const matcher_predicate<F>& m, const T& t) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x > t; });
|
||||
}
|
||||
template<class F>
|
||||
auto operator!(const matcher_predicate<F>& m) {
|
||||
return make_matcher_predicate([m](const auto& x) {return !m.f_(x); });
|
||||
}
|
||||
|
||||
template<class F, class F2>
|
||||
auto operator&&(const matcher_predicate<F>& m, const matcher_predicate<F2>& m2) {
|
||||
return make_matcher_predicate([m, m2](const auto& x) {return m.f_(x) && m2.f_(x); });
|
||||
}
|
||||
|
||||
template<class F, class F2>
|
||||
auto operator||(const matcher_predicate<F>& m, const matcher_predicate<F2>& m2) {
|
||||
return make_matcher_predicate([m, m2](const auto& x) {return m.f_(x) || m2.f_(x); });
|
||||
}
|
||||
|
||||
template<class F, class T>
|
||||
auto operator==(const T& t, const matcher_predicate<F>& m) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t == x; });
|
||||
}
|
||||
|
||||
template<class F, class T>
|
||||
auto operator!=(const T& t, const matcher_predicate<F>& m) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t != x; });
|
||||
}
|
||||
|
||||
template<class F, class T>
|
||||
auto operator<=(const T& t, const matcher_predicate<F>& m) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t <= x; });
|
||||
}
|
||||
template<class F, class T>
|
||||
auto operator>=(const T& t, const matcher_predicate<F>& m) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t >= x; });
|
||||
}
|
||||
template<class F, class T>
|
||||
auto operator<(const T& t, const matcher_predicate<F>& m) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t < x; });
|
||||
}
|
||||
template<class F, class T>
|
||||
auto operator>(const T& t, const matcher_predicate<F>& m) {
|
||||
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t > x; });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
// We use this class, so we can differentiate between matcher <T,T> and matchter <T,std::tuple<T...>
|
||||
struct tuple_ignorer {};
|
||||
}
|
||||
|
||||
namespace customization {
|
||||
|
||||
template<class... A>
|
||||
const std::tuple<A...>& simple_match_get_tuple(const std::tuple<A...>& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
template<class... A>
|
||||
std::tuple<A...>& simple_match_get_tuple(std::tuple<A...>& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
struct tuple_adapter {
|
||||
|
||||
|
||||
template<size_t I, class T>
|
||||
static decltype(auto) get(T&& t) {
|
||||
using namespace simple_match::customization;
|
||||
return std::get<I>(simple_match_get_tuple(std::forward<T>(t)));
|
||||
}
|
||||
};
|
||||
|
||||
template<class Type, class... Args>
|
||||
struct matcher<Type, std::tuple<Args...>> {
|
||||
using tu = tuple_adapter<Type>;
|
||||
enum { tuple_len = sizeof... (Args) - 1};
|
||||
template<size_t pos, size_t last>
|
||||
struct helper {
|
||||
template<class T, class A>
|
||||
static bool check(T&& t, A&& a) {
|
||||
return match_check(tu::template get<pos>(std::forward<T>(t)), std::get<pos>(std::forward<A>(a)))
|
||||
&& helper<pos + 1, last>::check(std::forward<T>(t), std::forward<A>(a));
|
||||
|
||||
}
|
||||
|
||||
template<class T, class A>
|
||||
static auto get(T&& t, A&& a) {
|
||||
return std::tuple_cat(match_get(tu::template get<pos>(std::forward<T>(t)), std::get<pos>(std::forward<A>(a))),
|
||||
helper<pos + 1, last>::get(std::forward<T>(t), std::forward<A>(a)));
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t pos>
|
||||
struct helper<pos, pos> {
|
||||
template<class T, class A>
|
||||
static bool check(T&& t, A&& a) {
|
||||
return match_check(tu::template get<pos>(std::forward<T>(t)), std::get<pos>(std::forward<A>(a)));
|
||||
|
||||
}
|
||||
template<class T, class A>
|
||||
static auto get(T&& t, A&& a) {
|
||||
return match_get(tu::template get<pos>(std::forward<T>(t)), std::get<pos>(std::forward<A>(a)));
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T, class A>
|
||||
static bool check(T&& t, A&& a) {
|
||||
return helper<0, tuple_len - 1>::check(std::forward<T>(t), std::forward<A>(a));
|
||||
|
||||
}
|
||||
template<class T, class A>
|
||||
static auto get(T&& t, A&& a) {
|
||||
return helper<0, tuple_len - 1>::get(std::forward<T>(t), std::forward<A>(a));
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
// destructure a tuple or other adapted structure
|
||||
template<class... A>
|
||||
auto ds(A&& ... a) {
|
||||
return std::make_tuple(std::forward<A>(a)..., detail::tuple_ignorer{});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#include "implementation/some_none.hpp"
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
35
src/external/simple_match/include/simple_match/utility.hpp
vendored
Normal file
35
src/external/simple_match/include/simple_match/utility.hpp
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
// Copyright 2015 John R. Bandela
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef SIMPLE_MATCH_UTILITY_HPP_JRB_2015_09_11
|
||||
#define SIMPLE_MATCH_UTILITY_HPP_JRB_2015_09_11
|
||||
#include "simple_match.hpp"
|
||||
namespace simple_match {
|
||||
// tagged_tuple
|
||||
|
||||
template<class Type, class... Args>
|
||||
struct tagged_tuple :std::tuple<Args...> {
|
||||
using base = std::tuple<Args...>;
|
||||
template<class... A>
|
||||
tagged_tuple(A&&... a) :base{ std::forward<A>(a)... } {}
|
||||
};
|
||||
|
||||
// inheriting_tagged_tuple
|
||||
|
||||
template<class Base, class Type, class... Args>
|
||||
struct inheriting_tagged_tuple :Base,tagged_tuple<Type,Args...> {
|
||||
using base = tagged_tuple<Type,Args...>;
|
||||
template<class... A>
|
||||
inheriting_tagged_tuple(A&&... a) :base{ std::forward<A>(a)... } {}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user