ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
arithmetics.cpp
1#if !DOXYGEN
2
3#define ARG0 (*args)
4#define ARG1 (*(args+1))
5#define BOL(box) (box).Unbox<bool >()
6#define INT(box) (box).Unbox<integer>()
7#define ITF(box) double((box).Unbox<integer>() )
8#define BTF(box) double((box).Unbox<bool >() )
9#define FLT(box) (box).Unbox<double >()
10#define FUNC( name,...) Box name( Scope& scope, \
11 ArgIterator args, \
12 ArgIterator end ) \
13 { (void) scope; (void) args; (void) end; __VA_ARGS__ }
14
15#if !ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS
16# define TOINT(arg) arg
17#else
18# define TOINT(arg) integer(arg)
19#endif
20
21
22namespace alib { namespace expressions { namespace plugins {
23
24
25FUNC( ToBoolean , return args->Call<FIsTrue>(); )
26
27namespace {
28
29
30//##################################################################################################
31// ### Arithmetics - constants
32//##################################################################################################
33
34Box constTrue = true;
35Box constFalse = false;
36Box identity = nullptr;
37Box bool_false = false;
38Box bool_true = true;
39Box int_0 = integer( 0 );
40Box int_1 = integer( 1 );
41Box float_0 = 0.0;
42Box float_1 = 1.0;
43
44
45//##################################################################################################
46// ### Arithmetics - Functions
47//##################################################################################################
48FUNC( toInt_B , return integer(BOL(ARG0)); )
49FUNC( toInt_I , return ARG0; )
50FUNC( toInt_F , return integer(FLT(ARG0)); )
51FUNC( toFloat_B, return double (BOL(ARG0)); )
52FUNC( toFloat_I, return double (INT(ARG0)); )
53FUNC( toFloat_F, return ARG0; )
54
55FUNC( arrLen, return ARG0.UnboxLength(); )
56
57
58//##################################################################################################
59// ### Arithmetics - unary operations
60//##################################################################################################
61
62FUNC( pos , return ARG0; )
63FUNC( pos_B , return integer(BOL(ARG0)); )
64FUNC( neg_B , return - integer(BOL(ARG0)); )
65FUNC( neg_I , return -INT(ARG0); )
66FUNC( neg_F , return -FLT(ARG0); )
67FUNC( bitNot , return ~INT(ARG0); )
68FUNC( boolNot_B, return !BOL(ARG0); )
69FUNC( boolNot_I, return INT(ARG0) == integer(0); )
70FUNC( boolNot_F, return FLT(ARG0) == 0.0; )
71
72
73//##################################################################################################
74// ### Arithmetics - binary operations
75//##################################################################################################
76
77#if defined(_MSC_VER)
78 #pragma warning( push )
79 #pragma warning( disable : 4804 ) // unsafe use of type bool
80 #pragma warning( disable : 4805 ) // unsafe mix of type bool and int
81#endif
82
83FUNC( mul_BB, return BOL(ARG0) * BOL(ARG1) ; )
84FUNC( mul_BI, return BOL(ARG0) * INT(ARG1) ; )
85FUNC( mul_BF, return BOL(ARG0) * FLT(ARG1) ; )
86FUNC( mul_IB, return INT(ARG0) * BOL(ARG1) ; )
87FUNC( mul_II, return INT(ARG0) * INT(ARG1) ; )
88FUNC( mul_IF, return ITF(ARG0) * FLT(ARG1) ; )
89FUNC( mul_FB, return FLT(ARG0) * BTF(ARG1) ; )
90FUNC( mul_FI, return FLT(ARG0) * ITF(ARG1) ; )
91FUNC( mul_FF, return FLT(ARG0) * FLT(ARG1) ; )
92FUNC( div_BI, return BOL(ARG0) / INT(ARG1) ; )
93FUNC( div_BF, return BOL(ARG0) / FLT(ARG1) ; )
94FUNC( div_II, return INT(ARG0) / INT(ARG1) ; )
95FUNC( div_IF, return ITF(ARG0) / FLT(ARG1) ; )
96FUNC( div_FI, return FLT(ARG0) / ITF(ARG1) ; )
97FUNC( div_FF, return FLT(ARG0) / FLT(ARG1) ; )
98FUNC( mod_BI, return BOL(ARG0) % INT(ARG1) ; )
99FUNC( mod_II, return INT(ARG0) % INT(ARG1) ; )
100FUNC( mod_BF, return fmod(BOL(ARG0), FLT(ARG1)); )
101FUNC( mod_FI, return fmod(FLT(ARG0), INT(ARG1)); )
102FUNC( mod_IF, return fmod(INT(ARG0), FLT(ARG1)); )
103FUNC( mod_FF, return fmod(FLT(ARG0), FLT(ARG1)); )
104
105FUNC( add_BB, return BOL(ARG0) + BOL(ARG1) ; )
106FUNC( add_BI, return BOL(ARG0) + INT(ARG1) ; )
107FUNC( add_BF, return BOL(ARG0) + FLT(ARG1) ; )
108FUNC( add_IB, return INT(ARG0) + BOL(ARG1) ; )
109FUNC( add_II, return INT(ARG0) + INT(ARG1) ; )
110FUNC( add_IF, return ITF(ARG0) + FLT(ARG1) ; )
111FUNC( add_FB, return FLT(ARG0) + BOL(ARG1) ; )
112FUNC( add_FI, return FLT(ARG0) + ITF(ARG1) ; )
113FUNC( add_FF, return FLT(ARG0) + FLT(ARG1) ; )
114FUNC( sub_BB, return BOL(ARG0) - BOL(ARG1) ; )
115FUNC( sub_BI, return BOL(ARG0) - INT(ARG1) ; )
116FUNC( sub_BF, return BOL(ARG0) - FLT(ARG1) ; )
117FUNC( sub_IB, return INT(ARG0) - BOL(ARG1) ; )
118FUNC( sub_II, return INT(ARG0) - INT(ARG1) ; )
119FUNC( sub_IF, return ITF(ARG0) - FLT(ARG1) ; )
120FUNC( sub_FB, return FLT(ARG0) - BOL(ARG1) ; )
121FUNC( sub_FI, return FLT(ARG0) - ITF(ARG1) ; )
122FUNC( sub_FF, return FLT(ARG0) - FLT(ARG1) ; )
123
124FUNC( shfL_BI, return TOINT( BOL(ARG0) << INT(ARG1) ); )
125FUNC( shfL_IB, return INT(ARG0) << BOL(ARG1) ; )
126FUNC( shfL_II, return INT(ARG0) << INT(ARG1) ; )
127FUNC( shfR_BI, return TOINT( BOL(ARG0) << INT(ARG1) ); )
128FUNC( shfR_IB, return INT(ARG0) << BOL(ARG1) ; )
129FUNC( shfR_II, return INT(ARG0) >> INT(ARG1) ; )
130
131FUNC( sm_BB, return BOL(ARG0) < BOL(ARG1) ; )
132FUNC( sm_BI, return BOL(ARG0) < INT(ARG1) ; )
133FUNC( sm_BF, return isless(double(BOL(ARG0)), FLT(ARG1) ); )
134FUNC( sm_IB, return INT(ARG0) < BOL(ARG1) ; )
135FUNC( sm_II, return INT(ARG0) < INT(ARG1) ; )
136FUNC( sm_IF, return isless(double (INT(ARG0)), FLT(ARG1) ); )
137FUNC( sm_FB, return isless( FLT(ARG0) , double(BOL(ARG1))); )
138FUNC( sm_FI, return isless( FLT(ARG0) , double(INT(ARG1))); )
139FUNC( sm_FF, return isless( FLT(ARG0) , FLT(ARG1) ); )
140FUNC( smeq_BB, return BOL(ARG0) <= BOL(ARG1) ; )
141FUNC( smeq_BI, return BOL(ARG0) <= INT(ARG1) ; )
142FUNC( smeq_BF, return islessequal(double(BOL(ARG0)), FLT(ARG1) ); )
143FUNC( smeq_IB, return INT(ARG0) <= BOL(ARG1) ; )
144FUNC( smeq_II, return INT(ARG0) <= INT(ARG1) ; )
145FUNC( smeq_IF, return islessequal(double(INT(ARG0)), FLT(ARG1) ); )
146FUNC( smeq_FB, return islessequal( FLT(ARG0) , double(BOL(ARG1))); )
147FUNC( smeq_FI, return islessequal( FLT(ARG0) , double(INT(ARG1))); )
148FUNC( smeq_FF, return islessequal( FLT(ARG0) , FLT(ARG1) ); )
149FUNC( gt_BB, return BOL(ARG0) > BOL(ARG1) ; )
150FUNC( gt_BI, return BOL(ARG0) > INT(ARG1) ; )
151FUNC( gt_BF, return isgreater(double(BOL(ARG0)), FLT(ARG1) ); )
152FUNC( gt_IB, return INT(ARG0) > BOL(ARG1) ; )
153FUNC( gt_II, return INT(ARG0) > INT(ARG1) ; )
154FUNC( gt_IF, return isgreater(double(INT(ARG0)), FLT(ARG1) ); )
155FUNC( gt_FB, return isgreater( FLT(ARG0) , double(BOL(ARG1))); )
156FUNC( gt_FI, return isgreater( FLT(ARG0) , double(INT(ARG1))); )
157FUNC( gt_FF, return isgreater( FLT(ARG0) , FLT(ARG1) ); )
158FUNC( gteq_BB, return BOL(ARG0) >= BOL(ARG1) ; )
159FUNC( gteq_BI, return BOL(ARG0) >= INT(ARG1) ; )
160FUNC( gteq_BF, return isgreaterequal(double(BOL(ARG0)), FLT(ARG1) ); )
161FUNC( gteq_IB, return INT(ARG0) >= BOL(ARG1) ; )
162FUNC( gteq_II, return INT(ARG0) >= INT(ARG1) ; )
163FUNC( gteq_IF, return isgreaterequal(double(INT(ARG0)), FLT(ARG1) ); )
164FUNC( gteq_FB, return isgreaterequal( FLT(ARG0) , double(BOL(ARG1))); )
165FUNC( gteq_FI, return isgreaterequal( FLT(ARG0) , double(INT(ARG1))); )
166FUNC( gteq_FF, return isgreaterequal( FLT(ARG0) , FLT(ARG1) ); )
167
168FUNC( eq_BB, return BOL(ARG0) == BOL(ARG1) ; )
169FUNC( eq_BI, return BOL(ARG0) == INT(ARG1) ; )
170FUNC( eq_BF, return std::fabs( BOL(ARG0) - FLT(ARG1) ) <= std::numeric_limits<double>::epsilon(); )
171FUNC( eq_IB, return INT(ARG0) == BOL(ARG1) ; )
172FUNC( eq_II, return INT(ARG0) == INT(ARG1) ; )
173FUNC( eq_IF, return std::fabs( ITF(ARG0) - FLT(ARG1) ) <= std::numeric_limits<double>::epsilon(); )
174FUNC( eq_FB, return std::fabs( FLT(ARG0) - BOL(ARG1) ) <= std::numeric_limits<double>::epsilon(); )
175FUNC( eq_FI, return std::fabs( FLT(ARG0) - ITF(ARG1) ) <= std::numeric_limits<double>::epsilon(); )
176FUNC( eq_FF, return std::fabs( FLT(ARG0) - FLT(ARG1) ) <= std::numeric_limits<double>::epsilon(); )
177
178
179
180FUNC( neq_BB, return BOL(ARG0) != BOL(ARG1) ; )
181FUNC( neq_BI, return BOL(ARG0) != INT(ARG1) ; )
182FUNC( neq_BF, return std::fabs( BOL(ARG0) - FLT(ARG1) ) > std::numeric_limits<double>::epsilon(); )
183FUNC( neq_IB, return INT(ARG0) != BOL(ARG1) ; )
184FUNC( neq_II, return INT(ARG0) != INT(ARG1) ; )
185FUNC( neq_IF, return std::fabs( INT(ARG0) - INT(ARG1) ) > std::numeric_limits<double>::epsilon(); )
186FUNC( neq_FB, return std::fabs( FLT(ARG0) - BOL(ARG1) ) > std::numeric_limits<double>::epsilon(); )
187FUNC( neq_FI, return std::fabs( FLT(ARG0) - ITF(ARG1) ) > std::numeric_limits<double>::epsilon(); )
188FUNC( neq_FF, return std::fabs( FLT(ARG0) - FLT(ARG1) ) > std::numeric_limits<double>::epsilon(); )
189
190
191FUNC( bitAnd, return INT(ARG0) & INT(ARG1) ; )
192FUNC( bitXOr, return INT(ARG0) ^ INT(ARG1) ; )
193FUNC( bitOr , return INT(ARG0) | INT(ARG1) ; )
194FUNC( boolAnd_BB, return BOL(ARG0) && BOL(ARG1) ; )
195FUNC( boolAnd_BI, return BOL(ARG0) && INT(ARG1) != 0 ; )
196FUNC( boolAnd_BF, return BOL(ARG0) && FLT(ARG1) != 0.0 ; )
197FUNC( boolAnd_IB, return INT(ARG0) != 0 && BOL(ARG1) ; )
198FUNC( boolAnd_II, return INT(ARG0) != 0 && INT(ARG1) != 0 ; )
199FUNC( boolAnd_IF, return INT(ARG0) != 0 && FLT(ARG1) != 0.0 ; )
200FUNC( boolAnd_FB, return FLT(ARG0) != 0.0 && BOL(ARG1) ; )
201FUNC( boolAnd_FI, return FLT(ARG0) != 0.0 && INT(ARG1) != 0 ; )
202FUNC( boolAnd_FF, return FLT(ARG0) != 0.0 && FLT(ARG1) != 0.0 ; )
203FUNC( boolOr_BB, return BOL(ARG0) || BOL(ARG1) ; )
204FUNC( boolOr_BI, return BOL(ARG0) || INT(ARG1) != 0 ; )
205FUNC( boolOr_BF, return BOL(ARG0) || FLT(ARG1) != 0.0 ; )
206FUNC( boolOr_IB, return INT(ARG0) != 0 || BOL(ARG1) ; )
207FUNC( boolOr_II, return INT(ARG0) != 0 || INT(ARG1) != 0 ; )
208FUNC( boolOr_IF, return INT(ARG0) != 0 || FLT(ARG1) != 0.0 ; )
209FUNC( boolOr_FB, return FLT(ARG0) != 0.0 || BOL(ARG1) ; )
210FUNC( boolOr_FI, return FLT(ARG0) != 0.0 || INT(ARG1) != 0 ; )
211FUNC( boolOr_FF, return FLT(ARG0) != 0.0 || FLT(ARG1) != 0.0 ; )
212
213#if defined(_MSC_VER)
214 #pragma warning( pop )
215#endif
216
217Calculus::OperatorTableEntry OperatorTable[] =
218{
219 // unary operators
230
231 // binary operators
352};
353
354Calculus::OperatorAliasTableEntry bitwiseOpsAliasBooleanOps[] =
355{
356 { A_CHAR("&"), Types::Boolean, Types::Boolean ,A_CHAR("&&") },
357 { A_CHAR("&"), Types::Boolean, Types::Integer ,A_CHAR("&&") },
358 { A_CHAR("&"), Types::Boolean, Types::Float ,A_CHAR("&&") },
359 { A_CHAR("&"), Types::Integer, Types::Boolean ,A_CHAR("&&") },
360 { A_CHAR("&"), Types::Float , Types::Boolean ,A_CHAR("&&") },
361 { A_CHAR("|"), Types::Boolean, Types::Boolean ,A_CHAR("||") },
362 { A_CHAR("|"), Types::Boolean, Types::Integer ,A_CHAR("||") },
363 { A_CHAR("|"), Types::Boolean, Types::Float ,A_CHAR("||") },
364 { A_CHAR("|"), Types::Integer, Types::Boolean ,A_CHAR("||") },
365 { A_CHAR("|"), Types::Float , Types::Boolean ,A_CHAR("||") },
366};
367
368Calculus::BinaryOpOptimizationsTableEntry binaryOperatorOptimizations[] =
369{
370 // optimizations with LEFT side constant value
371 { A_CHAR("||"), lang::Side::Left , bool_true , Types::Boolean, bool_true },
372 { A_CHAR("||"), lang::Side::Left , bool_false, Types::Boolean, identity },
373 { A_CHAR("&&"), lang::Side::Left , bool_true , Types::Boolean, identity },
374 { A_CHAR("&&"), lang::Side::Left , bool_false, Types::Boolean, bool_false },
375
376 { A_CHAR("+") , lang::Side::Left , int_0 , Types::Integer, identity },
377 { A_CHAR("+") , lang::Side::Left , float_0 , Types::Float , identity },
378 { A_CHAR("-") , lang::Side::Left , int_0 , Types::Integer, identity },
379 { A_CHAR("-") , lang::Side::Left , float_0 , Types::Float , identity },
380
381 { A_CHAR("*") , lang::Side::Left , int_0 , Types::Integer, int_0 },
382 { A_CHAR("*") , lang::Side::Left , int_1 , Types::Integer, identity },
383 { A_CHAR("*") , lang::Side::Left , float_0 , Types::Float , float_0 },
384 { A_CHAR("*") , lang::Side::Left , float_1 , Types::Float , identity },
385
386
387 // optimizations with RIGHT side constant value (repeat from above)
388 { A_CHAR("||"), lang::Side::Right, bool_true , Types::Boolean, bool_true },
389 { A_CHAR("||"), lang::Side::Right, bool_false, Types::Boolean, identity },
390 { A_CHAR("&&"), lang::Side::Right, bool_true , Types::Boolean, identity },
391 { A_CHAR("&&"), lang::Side::Right, bool_false, Types::Boolean, bool_false },
392
393 { A_CHAR("+") , lang::Side::Right, int_0 , Types::Integer, identity },
394 { A_CHAR("+") , lang::Side::Right, float_0 , Types::Float , identity },
395 { A_CHAR("-") , lang::Side::Right, int_0 , Types::Integer, identity },
396 { A_CHAR("-") , lang::Side::Right, float_0 , Types::Float , identity },
397
398 { A_CHAR("*") , lang::Side::Right, int_0 , Types::Integer, int_0 },
399 { A_CHAR("*") , lang::Side::Right, int_1 , Types::Integer, identity },
400 { A_CHAR("*") , lang::Side::Right, float_0 , Types::Float , float_0 },
401 { A_CHAR("*") , lang::Side::Right, float_1 , Types::Float , identity },
402
403 // further optimizations with RIGHT side constant value (not available for left-side)
404 { A_CHAR("/") , lang::Side::Right, int_1 , Types::Integer, identity },
405 { A_CHAR("/") , lang::Side::Right, int_1 , Types::Float , identity },
406 { A_CHAR("/") , lang::Side::Right, float_1 , Types::Float , identity },
407
408 { A_CHAR("%") , lang::Side::Right, int_1 , Types::Integer, identity },
409 { A_CHAR("%") , lang::Side::Right, int_1 , Types::Float , identity },
410 { A_CHAR("%") , lang::Side::Right, float_1 , Types::Float , identity },
411};
412
413
414} // anonymous namespace
415
416
417//##################################################################################################
418// ### Arithmetics - Constructor. Creates the hash map
419//##################################################################################################
421: Calculus( "ALib Arithmetics", compiler, CompilePriorities::Arithmetics ) {
422 constexpr int tableSize= 9;
423 Token functionNames[tableSize];
424 strings::util::LoadResourcedTokens( EXPRESSIONS, "CPA", functionNames
425 ALIB_DBG(,tableSize) );
426 Token* descriptor= functionNames;
427 ConstantIdentifiers=
428 {
429 { *descriptor++, constTrue },
430 { *descriptor++, constFalse },
431 { *descriptor++, constTrue },
432 { *descriptor++, constFalse },
433 { *descriptor++, constTrue },
434 { *descriptor++, constFalse },
435 };
436
437 Functions=
438 {
439 { *descriptor++, CALCULUS_SIGNATURE(Signatures::Var), CALCULUS_CALLBACK(ToBoolean), &Types::Boolean , CTI },
440 { *descriptor , CALCULUS_SIGNATURE(Signatures::B ), CALCULUS_CALLBACK(toInt_B ), &Types::Integer , CTI },
441 { *descriptor , CALCULUS_SIGNATURE(Signatures::I ), CALCULUS_CALLBACK(toInt_I ), &Types::Integer , CTI },
442 { *descriptor++, CALCULUS_SIGNATURE(Signatures::F ), CALCULUS_CALLBACK(toInt_F ), &Types::Integer , CTI },
443 { *descriptor , CALCULUS_SIGNATURE(Signatures::B ), CALCULUS_CALLBACK(toFloat_B), &Types::Float , CTI },
444 { *descriptor , CALCULUS_SIGNATURE(Signatures::I ), CALCULUS_CALLBACK(toFloat_I), &Types::Float , CTI },
445 { *descriptor++, CALCULUS_SIGNATURE(Signatures::F ), CALCULUS_CALLBACK(toFloat_F), &Types::Float , CTI },
446 };
447
448 AddOperators( OperatorTable );
449
450 if( HasBits(compiler.CfgCompilation, Compilation::AllowBitwiseBooleanOperators ) ) {
451 AddOperatorAliases( bitwiseOpsAliasBooleanOps );
452 AddOperatorAlias ( A_CHAR("~"), Types::Boolean, Types::Void, A_CHAR("!") );
453 }
454
455 AddBinaryOpOptimizations( binaryOperatorOptimizations);
456
457 ALIB_ASSERT_ERROR( descriptor - functionNames == tableSize, "EXPR",
458 "Descriptor table size mismatch: Consumed {} descriptors, {} available.",
459 descriptor - functionNames, tableSize)
460}
461
462bool Arithmetics::TryCompilation( CIFunction& ciFunction ) {
463 if( Calculus::TryCompilation( ciFunction ) )
464 return true;
465
466 if( ciFunction.QtyArgs() == 1 && ciFunction.ArgsBegin->IsArray() ) {
467 constexpr int tableSize= 1;
468 Token functionNames[tableSize];
469
470 strings::util::LoadResourcedTokens( EXPRESSIONS, "CPALen", functionNames
471 ALIB_DBG(,tableSize) );
472
473 if( functionNames[0].Match( ciFunction.Name ) ) {
474 ciFunction.Name.Reset( functionNames[0] );
475ALIB_DBG( ciFunction.DbgCallbackName = "arrLen"; )
476
477 // for constants, the callback might b invoked right away (optimizing call out)
478 if( ciFunction.AllArgsAreConst ) {
479 ciFunction.TypeOrValue = ciFunction.ArgsBegin->UnboxLength();
480 return true;
481 }
482
483 ciFunction.Callback = arrLen;
484 ciFunction.TypeOrValue = Types::Integer;
485
486 return true;
487 } }
488
489 return false;
490}
491
492}}} // namespace [alib::expressions::detail]
493
494#undef BOL
495#undef INT
496#undef FLT
497#undef FUNC
498#undef FUNC
499#undef UN_MAP_ENTRY
500#undef BIN_MAP_ENTRY
501#undef BIN_ALIAS_ENTRY
502
503
504#endif //DOXYGEN
#define A_CHAR(STR)
#define ALIB_DBG(...)
#define ALIB_ASSERT_ERROR(cond, domain,...)
#define CALCULUS_CALLBACK(func)
#define CALCULUS_SIGNATURE(BoxPointerArray)
constexpr bool HasBits(TEnum element, TEnum selection) noexcept
Definition bitwise.hpp:324
Box ToBoolean(Scope &scope, ArgIterator args, ArgIterator)
@ Right
Denotes the right side of something.
@ Left
Denotes the left side of something.
Definition alox.cpp:14
lang::integer integer
Type alias in namespace #"%alib".
Definition integers.hpp:149
boxing::Box Box
Type alias in namespace #"%alib".
Definition box.hpp:1128
expressions::Compiler Compiler
Type alias in namespace #"%alib".
Definition compiler.hpp:535
boxing::FIsTrue FIsTrue
Type alias in namespace #"%alib".
strings::util::Token Token
Type alias in namespace #"%alib".
Definition token.hpp:396
static Box Integer
Sample type-box for integer types. (Precisely for type #"lang::integer".).
static Box Boolean
Sample type-box for C++ type bool.
static Box Void
Sample type-box for C++ type void.
static Box Float
Sample type-box for C++ type double.
const std::tuple< String, Type, Type, CallbackDecl, Type, CTInvokable > OperatorTableEntry
Definition calculus.hpp:445
const std::tuple< String, lang::Side, Type, const Box &, const Box & > BinaryOpOptimizationsTableEntry
Definition calculus.hpp:620
static constexpr CTInvokable CTI
Definition calculus.hpp:235
const std::tuple< String, Type, Type, String > OperatorAliasTableEntry
Definition calculus.hpp:458