1919
2020#include " foundation-private.h"
2121
22+ #include < limits>
23+
2224// //////////////////////////////////////////////////////////////////////////////
2325
2426MC_DLLEXPORT_DEF MCTypeInfoRef kMCBoolTypeInfo ;
@@ -180,6 +182,15 @@ bool __MCForeignValueCopyDescription(__MCForeignValue *self, MCStringRef& r_desc
180182
181183// //////////////////////////////////////////////////////////////////////////////
182184
185+ static bool
186+ __throw_numeric_overflow (MCTypeInfoRef p_error, MCTypeInfoRef p_type)
187+ {
188+ return MCErrorCreateAndThrow (p_error,
189+ " type" , p_type,
190+ " reason" , MCSTR (" numeric overflow" ),
191+ nil);
192+ }
193+
183194// bool foreign type handlers
184195
185196static void __bool_finalize (void *)
@@ -329,39 +340,52 @@ __size_import (void *contents,
329340 bool release,
330341 MCValueRef & r_value)
331342{
332- size_t t_value = *( size_t *) contents;
343+ size_t t_value = *static_cast < size_t *>( contents) ;
333344
334- if (t_value > UINTEGER_MAX )
335- {
336- MCErrorCreateAndThrow (kMCForeignImportErrorTypeInfo ,
337- " type" , kMCSizeTypeInfo ,
338- " reason" , MCSTR (" too large for Number representation" ),
339- nil);
340- return false ;
345+ if (t_value <= UINTEGER_MAX )
346+ {
347+ return MCNumberCreateWithUnsignedInteger (uinteger_t (t_value),
348+ reinterpret_cast <MCNumberRef&>(r_value));
349+ }
350+ #ifdef __64_BIT__
351+ else if (t_value <= (1ULL << std::numeric_limits<double >::digits))
352+ {
353+ return MCNumberCreateWithReal (double (t_value),
354+ reinterpret_cast <MCNumberRef&>(r_value));
355+ }
356+ #endif
357+ else
358+ {
359+ return __throw_numeric_overflow (kMCForeignImportErrorTypeInfo ,
360+ kMCSizeTypeInfo );
341361 }
342-
343- return MCNumberCreateWithUnsignedInteger ((uinteger_t ) t_value,
344- (MCNumberRef &) r_value);
345362}
346363
347364static bool
348365__ssize_import (void *contents,
349366 bool release,
350367 MCValueRef & r_value)
351368{
352- ssize_t t_value = *( ssize_t *) contents;
369+ ssize_t t_value = *static_cast < ssize_t *>( contents) ;
353370
354- if (t_value < INTEGER_MIN || t_value > INTEGER_MAX )
355- {
356- MCErrorCreateAndThrow (kMCForeignImportErrorTypeInfo ,
357- " type" , kMCSizeTypeInfo ,
358- " reason" , MCSTR (" too large for Number representation" ),
359- nil);
360- return false ;
371+ if (t_value >= INTEGER_MIN && t_value <= INTEGER_MAX )
372+ {
373+ return MCNumberCreateWithInteger (integer_t (t_value),
374+ reinterpret_cast <MCNumberRef&>(r_value));
375+ }
376+ #ifdef __64_BIT__
377+ else if (t_value >= -(1LL << std::numeric_limits<double >::digits) &&
378+ t_value <= (1LL << std::numeric_limits<double >::digits))
379+ {
380+ return MCNumberCreateWithReal (double (t_value),
381+ reinterpret_cast <MCNumberRef&>(r_value));
382+ }
383+ #endif
384+ else
385+ {
386+ return __throw_numeric_overflow (kMCForeignImportErrorTypeInfo ,
387+ kMCSSizeTypeInfo );
361388 }
362-
363- return MCNumberCreateWithInteger ((integer_t ) t_value,
364- (MCNumberRef &) r_value);
365389}
366390
367391static bool __float_import (void *contents, bool release, MCValueRef& r_value)
@@ -374,47 +398,64 @@ static bool __double_import(void *contents, bool release, MCValueRef& r_value)
374398 return MCNumberCreateWithReal (*(double *)contents, (MCNumberRef&)r_value);
375399}
376400
377- static bool __int_export (MCValueRef value, bool release, void *contents)
378- {
379- *(integer_t *)contents = MCNumberFetchAsInteger ((MCNumberRef)value);
380- if (release)
381- MCValueRelease (value);
382- return true ;
383- }
384-
385401template <typename T>
386402static bool
387- __uint_export (MCValueRef value,
388- bool release,
389- void *contents,
390- MCTypeInfoRef typeinfo)
391- {
392- /* Unsigned values can't be negative */
393- if (0 > MCNumberFetchAsReal ((MCNumberRef) value))
394- {
395- MCErrorCreateAndThrow (kMCForeignExportErrorTypeInfo ,
396- " type" , typeinfo,
397- " reason" , MCSTR (" cannot store negative value in unsigned integer" ),
398- nil);
399- return false ;
400- }
403+ __any_int_export (MCValueRef value,
404+ bool release,
405+ void *contents,
406+ MCTypeInfoRef typeinfo)
407+ {
408+ // Fetch the number as a double
409+ double t_value =
410+ MCNumberFetchAsReal (static_cast <MCNumberRef>(value));
411+
412+ // First check that the value is within the contiguous integer range
413+ // of doubles. If that succeeds, then check it fits within the target
414+ // integer type.
415+ if (t_value < double (-(1LL << std::numeric_limits<double >::digits)) ||
416+ t_value > double (1LL << std::numeric_limits<double >::digits) ||
417+ t_value < double (std::numeric_limits<T>::min ()) ||
418+ t_value > double (std::numeric_limits<T>::max ()))
419+ {
420+ return __throw_numeric_overflow (kMCForeignExportErrorTypeInfo ,
421+ typeinfo);
422+ }
401423
402- *(T *)contents = MCNumberFetchAsUnsignedInteger ((MCNumberRef)value );
424+ *(T *)contents = T (t_value );
403425
404426 if (release)
405427 MCValueRelease (value);
428+
406429 return true ;
407430}
408431
432+ static bool
433+ __int_export (MCValueRef value, bool release, void *contents)
434+ {
435+ return __any_int_export<integer_t >(value, release, contents, kMCIntTypeInfo );
436+ }
437+
409438static bool
410439__uint_export (MCValueRef value, bool release, void *contents)
411440{
412- return __uint_export<uinteger_t >(value, release, contents, kMCUIntTypeInfo );
441+ return __any_int_export<uinteger_t >(value, release, contents, kMCUIntTypeInfo );
442+ }
443+
444+ static bool
445+ __size_export (MCValueRef value, bool release, void *contents)
446+ {
447+ return __any_int_export<size_t >(value, release, contents, kMCSizeTypeInfo );
448+ }
449+
450+ static bool
451+ __ssize_export (MCValueRef value, bool release, void *contents)
452+ {
453+ return __any_int_export<ssize_t >(value, release, contents, kMCSSizeTypeInfo );
413454}
414455
415456static bool __float_export (MCValueRef value, bool release, void *contents)
416457{
417- *(float *)contents = MCNumberFetchAsReal ((MCNumberRef)value);
458+ *(float *)contents = float ( MCNumberFetchAsReal ((MCNumberRef)value) );
418459 if (release)
419460 MCValueRelease (value);
420461 return true ;
@@ -428,18 +469,6 @@ static bool __double_export(MCValueRef value, bool release, void *contents)
428469 return true ;
429470}
430471
431- static bool
432- __size_export (MCValueRef value, bool release, void *contents)
433- {
434- return __uint_export<size_t >(value, release, contents, kMCSizeTypeInfo );
435- }
436-
437- static bool
438- __ssize_export (MCValueRef value, bool release, void *contents)
439- {
440- return __uint_export<ssize_t >(value, release, contents, kMCSSizeTypeInfo );
441- }
442-
443472static bool
444473__bool_describe (void *contents,
445474 MCStringRef & r_string)
0 commit comments