Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pick Variant from Standalone Maybe #6856

Merged
merged 30 commits into from
Nov 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
45aba9b
refactor maybe: add variant
PragmaTwice Nov 9, 2021
7010891
maybe: add optional and tests
PragmaTwice Nov 11, 2021
ae926b5
maybe: add hash for optional & variant; support NullOpt for both opti…
PragmaTwice Nov 12, 2021
67be133
maybe: more notes
PragmaTwice Nov 13, 2021
30e2a0b
maybe: binary search impl for Variant::Visit
PragmaTwice Nov 13, 2021
e41efcf
maybe: add more relational operator to optional & variant
PragmaTwice Nov 18, 2021
cb9f4bb
maybe: add nonstd::string_view
PragmaTwice Nov 18, 2021
01be3c7
maybe: fix construct of optional & variant
PragmaTwice Nov 18, 2021
42ecdc1
maybe: support comparision for optional & variant
PragmaTwice Nov 19, 2021
fdbbadc
maybe: add monadic operations for optional
PragmaTwice Nov 19, 2021
f46a1bd
maybe: add error traits
PragmaTwice Nov 23, 2021
a07112f
maybe: add JUST and Maybe
PragmaTwice Nov 23, 2021
620c681
maybe: remove useless comment
PragmaTwice Nov 23, 2021
61fc090
maybe: add more test
PragmaTwice Nov 24, 2021
ee0666f
maybe: customizable JUST
PragmaTwice Nov 24, 2021
0e90621
maybe: add Map and Bind (AndThen) to Maybe
PragmaTwice Nov 24, 2021
eac99c1
maybe: re-design JustConfig
PragmaTwice Nov 26, 2021
faf244d
maybe: rename xxxT to xxxS
PragmaTwice Nov 26, 2021
12699a5
maybe: fix method names
PragmaTwice Nov 26, 2021
2b2545e
Merge branch 'master' of github.com:oneflow-Inc/oneflow into maybe
PragmaTwice Nov 26, 2021
405e709
maybe: add maybe to cmake
PragmaTwice Nov 26, 2021
31476a7
maybe: fix error traits
PragmaTwice Nov 29, 2021
0b89912
maybe: rename fields & add aggregate type checking
PragmaTwice Nov 29, 2021
605633a
maybe: move string_view to new file
PragmaTwice Nov 29, 2021
af6eb1e
maybe: rename fields for optional and error
PragmaTwice Nov 29, 2021
f905b2b
maybe: new Value (no index checking, protected method) and Get (has c…
PragmaTwice Nov 29, 2021
74be59d
maybe: remove DefaultArgument
PragmaTwice Nov 29, 2021
da224cf
Pick Variant from Standalone Maybe
PragmaTwice Nov 29, 2021
6aab4cb
Merge branch 'master' into maybe-variant
PragmaTwice Nov 29, 2021
058e5fb
Merge branch 'master' into maybe-variant
oneflow-ci-bot Nov 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmake/oneflow.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ foreach(oneflow_single_file ${oneflow_all_src})
continue()
endif()

if("${oneflow_single_file}" MATCHES "^${PROJECT_SOURCE_DIR}/oneflow/(core|user|xrt)/.*\\.(h|hpp)$")
if("${oneflow_single_file}" MATCHES "^${PROJECT_SOURCE_DIR}/oneflow/(core|user|xrt|maybe)/.*\\.(h|hpp)$")
if((NOT RPC_BACKEND MATCHES "GRPC") AND "${oneflow_single_file}" MATCHES "^${PROJECT_SOURCE_DIR}/oneflow/core/control/.*")
# skip if GRPC not enabled
elseif(APPLE AND "${oneflow_single_file}" MATCHES "^${PROJECT_SOURCE_DIR}/oneflow/core/comm_network/(epoll|ibverbs)/.*")
Expand Down Expand Up @@ -228,8 +228,8 @@ foreach(oneflow_single_file ${oneflow_all_src})

endif(BUILD_PYTHON)

if("${oneflow_single_file}" MATCHES "^${PROJECT_SOURCE_DIR}/oneflow/(core|user|xrt)/.*\\.cpp$")
if("${oneflow_single_file}" MATCHES "^${PROJECT_SOURCE_DIR}/oneflow/(core|user|xrt)/.*_test\\.cpp$")
if("${oneflow_single_file}" MATCHES "^${PROJECT_SOURCE_DIR}/oneflow/(core|user|xrt|maybe)/.*\\.cpp$")
if("${oneflow_single_file}" MATCHES "^${PROJECT_SOURCE_DIR}/oneflow/(core|user|xrt|maybe)/.*_test\\.cpp$")
# test file
list(APPEND of_all_test_cc ${oneflow_single_file})
elseif(APPLE AND "${oneflow_single_file}" MATCHES "^${PROJECT_SOURCE_DIR}/oneflow/core/comm_network/(epoll|ibverbs)/.*")
Expand Down
52 changes: 52 additions & 0 deletions oneflow/maybe/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Copyright 2020 The OneFlow Authors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef ONEFLOW_MAYBE_CONFIG_H_
#define ONEFLOW_MAYBE_CONFIG_H_

#include <cassert>

// pre-define it if you use a logging library like glog
#ifndef OF_MAYBE_ASSERT
#define OF_MAYBE_ASSERT(_cond_) assert(_cond_)
#endif

// ASSERT_EQ is different from ASSERT in logging / testing framework
// pre-define it if you use a logging library like glog
#ifndef OF_MAYBE_ASSERT_EQ
#define OF_MAYBE_ASSERT_EQ(_lhs_, _rhs_) OF_MAYBE_ASSERT(_lhs_ == _rhs_)
#endif

#if __GNUC__ >= 7
#define OF_MAYBE_HAS_IS_AGGREGATE
// in old versions of clang, __has_builtin(__is_aggregate) returns false
#elif __clang__
#if !__is_identifier(__is_aggregate)
#define OF_MAYBE_HAS_IS_AGGREGATE
#endif
#elif __has_builtin(__is_aggregate)
#define OF_MAYBE_HAS_IS_AGGREGATE
#endif

#ifdef OF_MAYBE_HAS_IS_AGGREGATE
#define OF_MAYBE_IS_AGGREGATE(...) __is_aggregate(__VA_ARGS__)
#else
// decay to POD checking if no such builtin (because implementing __is_aggregate need reflection)
#define OF_MAYBE_IS_AGGREGATE(...) \
std::is_standard_layout<__VA_ARGS__>::value&& std::is_trivial<__VA_ARGS__>::value
#endif

#endif // ONEFLOW_MAYBE_CONFIG_H_
152 changes: 152 additions & 0 deletions oneflow/maybe/type_traits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
Copyright 2020 The OneFlow Authors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef ONEFLOW_MAYBE_TYPE_TRAITS_H_
#define ONEFLOW_MAYBE_TYPE_TRAITS_H_

#include <cstddef>
#include <type_traits>
#include <tuple>
#include <utility>
#include "config.h"

namespace oneflow {

namespace maybe {
hjchen2 marked this conversation as resolved.
Show resolved Hide resolved

// in this file, xxxS represents struct of xxx
hjchen2 marked this conversation as resolved.
Show resolved Hide resolved
// for implementant aspect, xxx is an alias of xxxS::type or xxxS::value

template<bool B>
using BoolConstant = std::integral_constant<bool, B>;
daquexian marked this conversation as resolved.
Show resolved Hide resolved

template<std::size_t I>
using IndexConstant = std::integral_constant<std::size_t, I>;

constexpr std::size_t NPos = -1;

template<typename...>
struct ConjS : std::true_type {};
template<typename B1>
struct ConjS<B1> : B1 {};
template<typename B1, typename... Bn>
struct ConjS<B1, Bn...> : std::conditional_t<bool(B1::value), ConjS<Bn...>, B1> {};

template<typename... B>
constexpr bool Conj = ConjS<B...>::value;

template<typename...>
struct DisjS : std::false_type {};
template<typename B1>
struct DisjS<B1> : B1 {};
template<typename B1, typename... Bn>
struct DisjS<B1, Bn...> : std::conditional_t<bool(B1::value), B1, DisjS<Bn...>> {};

template<typename... B>
constexpr bool Disj = DisjS<B...>::value;
hjchen2 marked this conversation as resolved.
Show resolved Hide resolved

template<typename B>
struct NegS : BoolConstant<!bool(B::value)> {};

template<typename B>
constexpr bool Neg = NegS<B>::value;

struct TypeNotFound;

// return TypeNotFound while out of range
template<std::size_t I, typename... Tn>
struct TypeGetS;

template<std::size_t I, typename T1, typename... Tn>
struct TypeGetS<I, T1, Tn...> : TypeGetS<I - 1, Tn...> {};

template<typename T1, typename... Tn>
struct TypeGetS<0, T1, Tn...> {
using type = T1;
};
hjchen2 marked this conversation as resolved.
Show resolved Hide resolved

template<std::size_t N>
struct TypeGetS<N> {
using type = TypeNotFound;
};

template<std::size_t I, typename... Ts>
using TypeGet = typename TypeGetS<I, Ts...>::type;

// return NPos (-1) while not found
template<std::size_t I, typename T, typename... Tn>
struct IndexGetFromS;

template<std::size_t I, typename T, typename T1, typename... Tn>
struct IndexGetFromS<I, T, T1, Tn...> : IndexGetFromS<I + 1, T, Tn...> {};

template<std::size_t I, typename T1, typename... Tn>
struct IndexGetFromS<I, T1, T1, Tn...> : IndexConstant<I> {};

template<std::size_t I, typename T>
struct IndexGetFromS<I, T> : IndexConstant<NPos> {};

template<typename T, typename... Ts>
constexpr auto IndexGet = IndexGetFromS<0, T, Ts...>::value;

template<typename T, typename... Ts>
constexpr auto TypeIn = IndexGet<T, Ts...> != NPos;

template<typename T, typename... Ts>
using TypeInS = BoolConstant<TypeIn<T, Ts...>>;

template<typename T>
struct RemoveCVRefS {
hjchen2 marked this conversation as resolved.
Show resolved Hide resolved
using type = std::remove_cv_t<std::remove_reference_t<T>>;
};

template<typename T>
using RemoveCVRef = typename RemoveCVRefS<T>::type;

template<typename T, typename... Ts>
struct IsDifferentTypesS : BoolConstant<!TypeIn<T, Ts...> && IsDifferentTypesS<Ts...>::value> {};

template<typename T>
struct IsDifferentTypesS<T> : std::true_type {};

template<typename T, typename... Ts>
constexpr auto IsDifferentTypes = IsDifferentTypesS<T, Ts...>::value;

template<typename T>
struct ConstRefExceptVoidS {
using type = const T&;
};

template<>
struct ConstRefExceptVoidS<void> {
using type = void;
};

template<typename T>
using ConstRefExceptVoid = typename ConstRefExceptVoidS<T>::type;

template<typename T>
using RemoveRValRef =
std::conditional_t<std::is_rvalue_reference<T>::value, std::remove_reference_t<T>, T>;

template<typename T>
constexpr bool IsAggregate = OF_MAYBE_IS_AGGREGATE(T);

} // namespace maybe

} // namespace oneflow

#endif // ONEFLOW_MAYBE_TYPE_TRAITS_H_
64 changes: 64 additions & 0 deletions oneflow/maybe/type_traits_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright 2020 The OneFlow Authors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <gtest/gtest.h>
#include <type_traits>
#include "oneflow/maybe/type_traits.h"

using namespace oneflow::maybe;

TEST(TypeTraits, Basics) {
static_assert(Conj<std::true_type, std::true_type>, "");
static_assert(!Conj<std::false_type, std::true_type>, "");
static_assert(!Conj<std::true_type, std::false_type>, "");
static_assert(!Conj<std::false_type, std::false_type>, "");
static_assert(!Conj<std::true_type, std::true_type, std::false_type>, "");

static_assert(Disj<std::true_type, std::true_type>, "");
static_assert(Disj<std::false_type, std::true_type>, "");
static_assert(Disj<std::true_type, std::false_type>, "");
static_assert(!Disj<std::false_type, std::false_type>, "");
static_assert(Disj<std::true_type, std::true_type, std::false_type>, "");
static_assert(!Disj<std::false_type, std::false_type, std::false_type>, "");

static_assert(std::is_same<TypeGet<0, int>, int>::value, "");
static_assert(std::is_same<TypeGet<0, int, float>, int>::value, "");
static_assert(std::is_same<TypeGet<1, int, float>, float>::value, "");
static_assert(std::is_same<TypeGet<2, int, float, bool, int>, bool>::value, "");
static_assert(std::is_same<TypeGet<2, int, int>, TypeNotFound>::value, "");
static_assert(std::is_same<TypeGet<2, int, int, float>, float>::value, "");
static_assert(std::is_same<TypeGet<2, int, int, float, int>, float>::value, "");
static_assert(std::is_same<TypeGet<2>, TypeNotFound>::value, "");

static_assert(IndexGet<int, int> == 0, "");
static_assert(IndexGet<int, float> == NPos, "");
static_assert(IndexGet<int, int, int> == 0, "");
static_assert(IndexGet<int, float, int> == 1, "");
static_assert(IndexGet<bool, int, float, int, bool, bool, int> == 3, "");
static_assert(IndexGet<int> == NPos, "");

static_assert(!TypeIn<int>, "");
static_assert(TypeIn<int, int>, "");
static_assert(TypeIn<int, float, int>, "");
static_assert(!TypeIn<int, float, float, bool>, "");
static_assert(TypeIn<int, float, bool, int, float>, "");
static_assert(TypeIn<bool, float, float, bool>, "");

static_assert(IsDifferentTypes<int, float, bool>, "");
static_assert(!IsDifferentTypes<int, float, int, bool>, "");
static_assert(IsDifferentTypes<int>, "");
static_assert(!IsDifferentTypes<int, int>, "");
}
89 changes: 89 additions & 0 deletions oneflow/maybe/utility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
Copyright 2020 The OneFlow Authors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef ONEFLOW_MAYBE_UTILITY_H_
#define ONEFLOW_MAYBE_UTILITY_H_

#include <cstddef>
#include <functional>

namespace oneflow {

namespace maybe {

// unlike std::nullopt in c++17, the NullOptType is used in both Variant and Optional,
// so it is more like both std::nullopt and std::monostate (in c++17),
// the advantage of this unification is a more unifed experience,
// i.e. `return NullOpt` can be used in both Variant and Optional context
struct NullOptType {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NullOpt其实从字面意思上讲就是专门给Optional用的,这里强行合并感觉不大好。如果只是为了统一一些接口的话,是不是可以提供一个基类,NullOpt和monostate都继承一个公共的基类

Copy link
Contributor Author

@PragmaTwice PragmaTwice Nov 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

因为我定义了一个 using OptionalVariant<T...> = Variant<NullOpt, T...> 类型,所以 NullOpt 在 Variant 中的含义很容易被解释通(Variant 本身是不允许存在 null 状态的,除了一些比较极端的情况)。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

那这个注释最好也把Variant改成OptionalVariant

explicit constexpr NullOptType() = default;

bool operator==(NullOptType) const { return true; }
bool operator!=(NullOptType) const { return false; }
bool operator<(NullOptType) const { return false; }
bool operator>(NullOptType) const { return false; }
bool operator<=(NullOptType) const { return true; }
bool operator>=(NullOptType) const { return true; }
};

constexpr const std::size_t NullOptHash = -3333;

constexpr NullOptType NullOpt{};

struct InPlaceT {
explicit constexpr InPlaceT() = default;
};

constexpr InPlaceT InPlace;

template<typename T>
struct InPlaceTypeT {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InPlaceTypeT和InPlaceT的区别是?

Copy link
Contributor Author

@PragmaTwice PragmaTwice Nov 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InPlaceType 可以接受一个类型,比如 InPlaceType<int>,用来初始化 variant 到 int 类型。InPlace 是给 Optional 用的,用来初始化 optional 到存在值的类型,本身没有模板参数。(我重写了个不带 shared_ptr 的 Optional,这个 pr 里没有,在原本的那个 standalone maybe 里)

explicit constexpr InPlaceTypeT() = default;
};

template<typename T>
constexpr InPlaceTypeT<T> InPlaceType;

template<std::size_t I>
struct InPlaceIndexT {
explicit constexpr InPlaceIndexT() = default;
};

template<std::size_t I>
constexpr InPlaceIndexT<I> InPlaceIndex;

template<class T>
constexpr void HashCombine(std::size_t& seed, const T& v) {
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

} // namespace maybe

} // namespace oneflow

namespace std {

template<>
struct hash<oneflow::maybe::NullOptType> {
size_t operator()(oneflow::maybe::NullOptType) const noexcept {
return oneflow::maybe::NullOptHash;
}
};

} // namespace std

#endif // ONEFLOW_MAYBE_UTILITY_H_
Loading