-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNumeric.h
149 lines (132 loc) · 3.98 KB
/
Numeric.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#pragma once
#include "SValue.h"
#include <algorithm>
//#include <numeric>
#include <string>
#include <type_traits>
//template < typename Itr >
//class DataPointerIterator
//{
// Itr itr;
//
//public:
// constexpr explicit DataPointerIterator( Itr itr ) : itr( itr )
// {}
//
// constexpr auto operator*()
// {
// return ( *itr ).get();
// }
//
// constexpr auto operator++()
// {
// ++itr;
// return *this;
// }
// constexpr friend bool operator!=( DataPointerIterator< Itr > a, DataPointerIterator< Itr > b )
// {
// return a.itr != b.itr;
// }
//};
// v is an S-expression. e.g. 1 2 3 5
template < typename NumericT >
SValue* evaluateNumericT( const std::string& op, SValue* v )
{
static_assert(
std::is_integral_v< NumericT > || std::is_floating_point_v< NumericT >,
"evaluateNumeric must be used with integral or floating point types" );
Cells& cells = v->cellsRequired();
const bool allNumeric =
std::all_of( cells.begin(), cells.end(), []( const auto& s ) { return s->isType< NumericT >(); } );
REQUIRE( v, allNumeric, op + " Not all arguments are the same numeric type" );
// Negation
if ( op == "-" && cells.size() == 1 )
{
SValue* s = cells.front();
v->value = apply< NumericT >( s, std::negate< NumericT >() );
return v;
}
using AccumulatorFunc = std::function< Value( NumericT, NumericT ) >;
auto pickAccumulator = [ &op ]() -> AccumulatorFunc {
if ( op == "+" )
{
return []( NumericT x, NumericT y ) -> Value { return x + y; };
}
if ( op == "-" )
{
return []( NumericT x, NumericT y ) -> Value { return x - y; };
}
if ( op == "*" )
{
return []( NumericT x, NumericT y ) -> Value { return x * y; };
}
if ( op == "/" )
{
return []( NumericT x, NumericT y ) -> Value {
return y == 0 ? Value( Error( "Division by zero" ) ) : Value( x / y );
};
}
if ( op == "mod" )
{
return []( NumericT x, NumericT y ) -> Value {
if ( y == NumericT{ 0 } )
{
return Value( Error( "Modulus division by zero" ) );
}
if constexpr ( std::is_integral_v< NumericT > )
{
return Value( x % y );
}
else
{
// Fall back to float mod.
return std::fmod< double >( x, y );
}
};
}
return []( NumericT x, NumericT y ) -> Value { return Error( "Unsupported numerical operator" ); };
};
//auto integralOperator = [ &op ]() -> AccumulatorFunc {
// if ( op == "+" )
// {
// return []( SValue* x, SValue* y ) -> SValue* { return concat< NumericT >( x, y, std::plus< NumericT >() ); };
// }
// if ( op == "-" )
// {
// return []( SValue* x, SValue* y ) -> SValue* { return concat< NumericT >( x, y, std::minus< NumericT >() ); };
// }
// if ( op == "*" )
// {
// return
// []( SValue* x, SValue* y ) -> SValue* { return concat< NumericT >( x, y, std::multiplies< NumericT >() ); };
// }
// if ( op == "/" )
// {
// return []( SValue* x, SValue* y ) -> SValue* {
// if ( x->isError() )
// {
// return x; // Propagate error.
// }
// NumericT yvalue = std::get< NumericT >( y->value );
// REQUIRE( x, yvalue != NumericT{ 0 }, "Division by zero" );
// return concat< NumericT >( x, y, std::divides< NumericT >() );
// };
// }
// return []( SValue* x, SValue* ) -> SValue* { return error( x, "Unsupported numerical operator" ); };
//};
//SValue* finalValue = std::accumulate(
// DataPointerIterator( cells.begin() + 1 ), DataPointerIterator( cells.end() ), cells.front(), integralOperator() );
std::unique_ptr< SValue > first = cells.takeFront();
Value result = first->value;
auto accumulator = pickAccumulator();
while ( !cells.isEmpty() )
{
result = accumulator( std::get< NumericT >( result ), cells.takeFront()->get< NumericT >() );
if ( auto error = std::get_if< Error >( &result ) )
{
break;
}
}
v->value = result;
return v;
}