1 #Region "Microsoft.VisualBasic::d46bd0117a924034935616586fd3bdf9, Microsoft.VisualBasic.Core\Language\Value\DefaultValue\Default.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Delegate Function
35     
36     
37     '     Delegate Function
38     
39     
40     '     Interface IDefaultValue
41     
42     '         Properties: DefaultValue
43     
44     '     Interface IsEmpty
45     
46     '         Properties: IsEmpty
47     
48     '     Structure DefaultValue
49     
50     '         Properties: DefaultValue, IsEmpty
51     
52     '         Constructor: (+2 OverloadsSub New
53     '         Function: (+2 Overloads) [When], getDefault, GetNumericAssert, ToString
54     '         Operators: (+2 Overloads) +, (+6 OverloadsOr
55     
56     
57     
58     
59     
60     ' /********************************************************************************/
61
62 #End Region
63
64 Imports System.Linq.Expressions
65 Imports System.Runtime.CompilerServices
66 Imports Microsoft.VisualBasic.Language.Perl
67
68 Namespace Language.Default
69
70     Public Delegate Function Assert(Of T)(obj As T) As Boolean
71
72     ''' <summary>
73     ''' + Test of A eqauls to B?
74     ''' </summary>
75     ''' <typeparam name="T"></typeparam>
76     ''' <param name="x"></param>
77     ''' <param name="y"></param>
78     ''' <returns></returns>
79     Public Delegate Function BinaryAssert(Of T)(x As T, y As T) As Boolean
80
81     Public Interface IDefaultValue(Of T)
82         ReadOnly Property DefaultValue As T
83     End Interface
84
85     ''' <summary>
86     ''' Apply on the structure type that assert the object is null or not.
87     ''' </summary>
88     Public Interface IsEmpty
89         ReadOnly Property IsEmpty As Boolean
90     End Interface
91
92     ''' <summary>
93     ''' The default value
94     ''' </summary>
95     ''' <typeparam name="T"></typeparam>
96     Public Structure DefaultValue(Of T) : Implements IDefaultValue(Of T)
97         Implements IsEmpty
98
99         Public ReadOnly Property DefaultValue As T Implements IDefaultValue(Of T).DefaultValue
100             <MethodImpl(MethodImplOptions.AggressiveInlining)>
101             Get
102                 If LazyValue Is Nothing Then
103                     Return Value
104                 Else
105                     ' using lazy loading, if the default value takes time to creates.
106                     Return LazyValue.Value()
107                 End If
108             End Get
109         End Property
110
111         Public ReadOnly Property IsEmpty As Boolean Implements IsEmpty.IsEmpty
112             <MethodImpl(MethodImplOptions.AggressiveInlining)>
113             Get
114                 Return LazyValue Is Nothing AndAlso assert(Value)
115             End Get
116         End Property
117
118         ''' <summary>
119         ''' The default value for <see cref="DefaultValue"/>
120         ''' </summary>
121         Dim Value As T
122
123         ''' <summary>
124         ''' 假若生成目标值的时间比较久,可以将其申明为Lambda表达式,这样子可以进行惰性加载
125         ''' </summary>
126         Dim LazyValue As Lazy(Of T)
127
128         ''' <summary>
129         ''' asset that if target value is null?
130         ''' </summary>
131         Dim assert As Assert(Of Object)
132
133         ''' <summary>
134         ''' 这个判断函数优化了对数字类型的判断
135         ''' </summary>
136         ''' <param name="n"></param>
137         ''' <returns></returns>
138         ''' <remarks>
139         ''' 在VB之中,数值类型在未赋值的状态下默认值为零,意味着此时该数值的值为空
140         ''' 但是不清楚这样子判断是否会出现bug?
141         ''' </remarks>
142         Public Shared Function GetNumericAssert(n As ObjectAs Boolean
143             If n Is Nothing Then
144                 ' 可空类型的数值类型
145                 Return True
146             End If
147
148             Select Case n.GetType
149                 Case GetType(Integer), GetType(Long), GetType(ULong), GetType(UInteger), GetType(Short), GetType(UShort)
150                     Return CInt(n) = 0 OrElse CDbl(n).IsNaNImaginary
151                 Case GetType(Double), GetType(Single), GetType(Decimal)
152                     Return CDbl(n) = 0.0 OrElse CDbl(n).IsNaNImaginary
153                 Case Else
154 #If DEBUG Then
155                     Call n.GetType.FullName.Warning
156 #End If
157                     Return ExceptionHandle.Default(obj:=n)
158             End Select
159         End Function
160
161         Sub New(value As T, Optional assert As Assert(Of Object) = Nothing)
162             Me.Value = value
163             Me.assert = assert Or defaultAssert
164         End Sub
165
166         Sub New(lazy As Func(Of T), Optional assert As Assert(Of Object) = Nothing)
167             Me.LazyValue = lazy.AsLazy
168             Me.assert = assert Or defaultAssert
169         End Sub
170
171         Public Function [When](expression As BooleanAs DefaultValue(Of T)
172             assert = Function(null) expression
173             Return Me
174         End Function
175
176         Public Function [When](assert As Assert(Of T)) As DefaultValue(Of T)
177             Me.assert = Function(o) assert(DirectCast(o, T))
178             Return Me
179         End Function
180
181         Public Overrides Function ToString() As String
182             Return $"default({Value})"
183         End Function
184
185         ''' <summary>
186         ''' Add handler
187         ''' </summary>
188         ''' <param name="[default]"></param>
189         ''' <param name="assert"></param>
190         ''' <returns></returns>
191         ''' 
192         <MethodImpl(MethodImplOptions.AggressiveInlining)>
193         Public Shared Operator +([default] As DefaultValue(Of T), assert As Assert(Of Object)) As DefaultValue(Of T)
194             Return New DefaultValue(Of T) With {
195                 .assert = assert,
196                 .Value = [default].Value
197             }
198         End Operator
199
200         <MethodImpl(MethodImplOptions.AggressiveInlining)>
201         Public Shared Operator +([default] As DefaultValue(Of T), assert As Expression(Of Func(Of Boolean))) As DefaultValue(Of T)
202             Return New DefaultValue(Of T) With {
203                 .assert = Function(null) (assert.Compile())(),
204                 .Value = [default].Value
205             }
206         End Operator
207
208         ''' <summary>
209         ''' if <see cref="assert"/> is true, then will using default <see cref="value"/>, 
210         ''' otherwise, return the source <paramref name="obj"/>.
211         ''' </summary>
212         ''' <param name="obj"></param>
213         ''' <param name="[default]"></param>
214         ''' <returns></returns>
215         ''' 
216         <MethodImpl(MethodImplOptions.AggressiveInlining)>
217         Public Shared Operator Or(obj As T, [default] As DefaultValue(Of T)) As T
218             Return getDefault(obj, [default].DefaultValue, If([default].assert, ExceptionHandle.defaultHandler))
219         End Operator
220
221         <MethodImpl(MethodImplOptions.AggressiveInlining)>
222         Private Shared Function getDefault(value As T, [default] As T, assert As Assert(Of Object))
223             Return If(assert(value), [default], value)
224         End Function
225
226         <MethodImpl(MethodImplOptions.AggressiveInlining)>
227         Public Shared Operator Or([default] As DefaultValue(Of T), obj As T) As T
228             Return getDefault([default].DefaultValue, obj, If([default].assert, ExceptionHandle.defaultHandler))
229         End Operator
230
231         ''' <summary>
232         ''' 这个操作符允许链式计算默认值:
233         ''' 
234         ''' A OR B OR C OR x OR y OR z
235         ''' </summary>
236         ''' <param name="x"></param>
237         ''' <param name="y"></param>
238         ''' <returns></returns>
239         <MethodImpl(MethodImplOptions.AggressiveInlining)>
240         Public Shared Operator Or(x As DefaultValue(Of T), y As DefaultValue(Of T)) As T
241             Return x.DefaultValue Or y
242         End Operator
243
244         <MethodImpl(MethodImplOptions.AggressiveInlining)>
245         Public Shared Widening Operator CType(obj As T) As DefaultValue(Of T)
246             Return New DefaultValue(Of T) With {
247                 .Value = obj,
248                 .assert = AddressOf ExceptionHandle.Default
249             }
250         End Operator
251
252         <MethodImpl(MethodImplOptions.AggressiveInlining)>
253         Public Shared Narrowing Operator CType([default] As DefaultValue(Of T)) As T
254             Return [default].DefaultValue
255         End Operator
256
257         <MethodImpl(MethodImplOptions.AggressiveInlining)>
258         Public Shared Widening Operator CType(lazy As Func(Of T)) As DefaultValue(Of T)
259             Return New DefaultValue(Of T) With {
260                 .LazyValue = lazy.AsLazy,
261                 .assert = AddressOf ExceptionHandle.Default
262             }
263         End Operator
264     End Structure
265 End Namespace