• R/O
  • SSH
  • HTTPS

eirrepo: Commit


Commit MetaInfo

Revision171 (tree)
Time2018-12-25 16:46:01
Authorquiret

Log Message

- refactored sliceOfData into eir::mathSlice
- added official floating-point support for eir::mathSlice
- added unit tests for MathSlice.h header components
- moved eIntersectionResult into the eir namespace

Change Summary

Incremental Difference

--- common/sdk/MathSlice.h (nonexistent)
+++ common/sdk/MathSlice.h (revision 171)
@@ -0,0 +1,1070 @@
1+/*****************************************************************************
2+*
3+* PROJECT: Eir SDK
4+* LICENSE: See LICENSE in the top level directory
5+* FILE: eirrepo/sdk/MathSlice.h
6+* PURPOSE: Implementation of mathematical intervals
7+*
8+* Find the Eir SDK at: https://osdn.net/projects/eirrepo/
9+* Multi Theft Auto is available from http://www.multitheftauto.com/
10+*
11+*****************************************************************************/
12+
13+#ifndef _EIR_SDK_MATH_SLICE_HEADER_
14+#define _EIR_SDK_MATH_SLICE_HEADER_
15+
16+#include <type_traits>
17+#include <limits>
18+#include <algorithm>
19+
20+#include "MacroUtils.h"
21+#include "eirutils.h"
22+
23+namespace eir
24+{
25+
26+// Definition of an upper bound.
27+template <typename numberType>
28+struct upperBound
29+{
30+ // If we are an unsigned numberType we want to have the specialty that a maximum value is remapped to the value "-1"
31+ // meaning a value below all unsigned values. This is made to properly model empty intervals and is actually an
32+ // optimization trade-off.
33+
34+ AINLINE upperBound( void ) noexcept
35+ {
36+ this->data.value = 0;
37+
38+ if constexpr ( std::is_floating_point <numberType>::value )
39+ {
40+ this->data.isIncluded = true;
41+ }
42+ }
43+ AINLINE upperBound( numberType value ) noexcept
44+ {
45+ this->data.value = std::move( value );
46+
47+ if constexpr ( std::is_floating_point <numberType>::value )
48+ {
49+ this->data.isIncluded = true;
50+ }
51+ }
52+ // If isIncluded == true then this constructor will never throw an exception.
53+ AINLINE upperBound( numberType value, bool isIncluded ) noexcept(std::is_floating_point <numberType>::value)
54+ {
55+ if constexpr ( std::is_integral <numberType>::value )
56+ {
57+ if ( isIncluded == false )
58+ {
59+ if constexpr ( std::is_unsigned <numberType>::value )
60+ {
61+ // Special optimization: treat max as -1.
62+ if ( value == std::numeric_limits <numberType>::max() )
63+ {
64+ throw eir_exception();
65+ }
66+
67+ if ( value == std::numeric_limits <numberType>::min() )
68+ {
69+ value = std::numeric_limits <numberType>::max();
70+ }
71+ else
72+ {
73+ value--;
74+ }
75+ }
76+ else
77+ {
78+ // Regular range.
79+ if ( value == std::numeric_limits <numberType>::min() )
80+ {
81+ throw eir_exception();
82+ }
83+
84+ value--;
85+ }
86+ }
87+
88+ this->data.value = std::move( value );
89+ }
90+ else if constexpr ( std::is_floating_point <numberType>::value )
91+ {
92+ this->data.value = std::move( value );
93+ this->data.isIncluded = isIncluded;
94+ }
95+ else
96+ {
97+#ifdef _MSC_VER
98+ static_assert( false, "invalid numberType in advanced upperBound constructor" );
99+#endif //_MSC_VER
100+ }
101+ }
102+
103+ AINLINE upperBound( const upperBound& ) = default;
104+ AINLINE upperBound( upperBound&& ) = default;
105+
106+ AINLINE ~upperBound( void ) = default;
107+
108+ AINLINE upperBound& operator = ( const upperBound& ) = default;
109+ AINLINE upperBound& operator = ( upperBound&& ) = default;
110+
111+ AINLINE static upperBound minus_one( void )
112+ {
113+ if constexpr ( std::is_integral <numberType>::value && std::is_unsigned <numberType>::value )
114+ {
115+ return upperBound( std::numeric_limits <numberType>::max() );
116+ }
117+ else
118+ {
119+ return upperBound( -1 );
120+ }
121+ }
122+
123+ AINLINE void lowbound( numberType bound, bool isIncluded = true ) noexcept(std::is_floating_point <numberType>::value)
124+ {
125+ // Imagine how painful this stuff were if we did not have "constexpr-if".
126+ // You'd have to write method/class specializations for each case!
127+
128+ if constexpr ( std::is_integral <numberType>::value )
129+ {
130+ if constexpr ( std::is_unsigned <numberType>::value )
131+ {
132+ numberType curBound = this->data.value;
133+
134+ // Nothing can be smaller than -1.
135+ if ( curBound != std::numeric_limits <numberType>::max() )
136+ {
137+ if ( isIncluded == false )
138+ {
139+ if ( bound == std::numeric_limits <numberType>::max() )
140+ {
141+ // We do not support -2.
142+ throw eir_exception();
143+ }
144+
145+ if ( bound == std::numeric_limits <numberType>::min() )
146+ {
147+ bound = std::numeric_limits <numberType>::max();
148+ }
149+ else
150+ {
151+ bound--;
152+ }
153+ }
154+
155+ // Special case: treat max as -1.
156+ if ( bound == std::numeric_limits <numberType>::max() )
157+ {
158+ this->data.value = std::move( bound );
159+ }
160+ else
161+ {
162+ if ( bound < curBound )
163+ {
164+ this->data.value = bound;
165+ }
166+ }
167+ }
168+ }
169+ else
170+ {
171+ if ( isIncluded == false )
172+ {
173+ if ( bound == std::numeric_limits <numberType>::min() )
174+ {
175+ // I decided against storing the "alwaysFalse" condition inside the bounds for
176+ // integral values because it is such a rare condition that should be prevented
177+ // by the slice user. Otherwise we would pollute many memory and other logic
178+ // classes!
179+ throw eir_exception();
180+ }
181+
182+ bound--;
183+ }
184+
185+ if ( bound < this->data.value )
186+ {
187+ this->data.value = std::move( bound );
188+ }
189+ }
190+ }
191+ else if constexpr ( std::is_floating_point <numberType>::value )
192+ {
193+ numberType curBound = this->data.value;
194+
195+ if ( bound == curBound )
196+ {
197+ if ( isIncluded == false )
198+ {
199+ this->data.isIncluded = false;
200+ }
201+ }
202+ else if ( bound < curBound )
203+ {
204+ this->data.value = bound;
205+ this->data.isIncluded = isIncluded;
206+ }
207+ }
208+ else
209+ {
210+#ifdef _MSC_VER
211+ static_assert( false, "invalid numberType for upperBound::lowbound" );
212+#endif //_MSC_VER
213+ }
214+ }
215+
216+ // If we are a floating-point then we are a number that converges very close to our value from negative infinity.
217+
218+ // Operators between upperBounds.
219+ AINLINE friend bool operator <= ( const upperBound& left, const upperBound& right ) noexcept
220+ {
221+ if constexpr ( std::is_integral <numberType>::value )
222+ {
223+ if constexpr ( std::is_unsigned <numberType>::value )
224+ {
225+ // Remember that we are always inclusive in integral mode.
226+ numberType leftBound = left.data.value;
227+ numberType rightBound = right.data.value;
228+
229+ if ( leftBound == rightBound )
230+ {
231+ return true;
232+ }
233+
234+ // Special case: -1 is smaller equal than any value of bound.
235+ if ( leftBound == std::numeric_limits <numberType>::max() )
236+ {
237+ return true;
238+ }
239+
240+ // Special case: treat max as -1.
241+ if ( rightBound == std::numeric_limits <numberType>::max() )
242+ {
243+ return false;
244+ }
245+
246+ return ( leftBound <= rightBound );
247+ }
248+ else
249+ {
250+ return ( left.get_value() <= right.get_value() );
251+ }
252+ }
253+ else if constexpr ( std::is_floating_point <numberType>::value )
254+ {
255+ bool isSameIncluded = ( right.data.isIncluded );
256+
257+ if ( isSameIncluded )
258+ {
259+ return ( left.data.value <= right.data.value );
260+ }
261+ else
262+ {
263+ return ( left.data.value < right.data.value );
264+ }
265+ }
266+ else
267+ {
268+#ifdef _MSC_VER
269+ static_assert( false, "not implemented operator <= for numberType" );
270+#endif //_MSC_VER
271+ }
272+ }
273+ AINLINE friend bool operator > ( const upperBound& left, const upperBound& right ) noexcept
274+ {
275+ return !( operator <= ( left, right ) );
276+ }
277+ AINLINE friend bool operator >= ( const upperBound& left, const upperBound& right ) noexcept
278+ {
279+ return operator <= ( right, left );
280+ }
281+ AINLINE friend bool operator < ( const upperBound& left, const upperBound& right ) noexcept
282+ {
283+ return !( operator >= ( left, right ) );
284+ }
285+
286+ // Do not forget to implement equality properly.
287+
288+ AINLINE friend bool operator == ( const upperBound& left, const upperBound& right ) noexcept
289+ {
290+ if ( left.data.value != right.data.value )
291+ {
292+ return false;
293+ }
294+
295+ if constexpr ( std::is_floating_point <numberType>::value )
296+ {
297+ if ( left.data.isIncluded != right.data.isIncluded )
298+ {
299+ return false;
300+ }
301+ }
302+
303+ return true;
304+ }
305+ AINLINE friend bool operator != ( const upperBound& left, const upperBound& right ) noexcept
306+ {
307+ return !( operator == ( left, right ) );
308+ }
309+
310+ // Standard comparison with number.
311+ AINLINE bool is_bounded( const upperBound& right ) const noexcept
312+ {
313+ return ( right <= *this );
314+ }
315+
316+ AINLINE const numberType& get_value( void ) const noexcept
317+ {
318+ return this->data.value;
319+ }
320+
321+ AINLINE bool is_included( void ) const noexcept
322+ {
323+ if constexpr ( std::is_integral <numberType>::value )
324+ {
325+ return true;
326+ }
327+ else if constexpr ( std::is_floating_point <numberType>::value )
328+ {
329+ return this->data.isIncluded;
330+ }
331+ else
332+ {
333+ return false;
334+ }
335+ }
336+
337+private:
338+ struct fields_integral
339+ {
340+ numberType value;
341+ };
342+
343+ struct fields_floating_point
344+ {
345+ numberType value;
346+ bool isIncluded;
347+ };
348+
349+ typename std::conditional <std::is_floating_point <numberType>::value, fields_floating_point, fields_integral>::type data;
350+};
351+
352+// Definition of a lower bound.
353+template <typename numberType>
354+struct lowerBound
355+{
356+ AINLINE lowerBound( void ) noexcept
357+ {
358+ this->data.value = 0;
359+
360+ if constexpr ( std::is_floating_point <numberType>::value )
361+ {
362+ this->data.isIncluded = true;
363+ }
364+ }
365+ AINLINE lowerBound( numberType value ) noexcept
366+ {
367+ this->data.value = std::move( value );
368+
369+ if constexpr ( std::is_floating_point <numberType>::value )
370+ {
371+ this->data.isIncluded = true;
372+ }
373+ }
374+ // If isIncluded is true then this constructor will never throw an exception.
375+ AINLINE lowerBound( numberType value, bool isIncluded ) noexcept(std::is_floating_point <numberType>::value)
376+ {
377+ if constexpr ( std::is_integral <numberType>::value )
378+ {
379+ if ( isIncluded == false )
380+ {
381+ if ( value == std::numeric_limits <numberType>::min() )
382+ {
383+ throw eir_exception();
384+ }
385+
386+ value++;
387+ }
388+
389+ this->data.value = std::move( value );
390+ }
391+ else if constexpr ( std::is_floating_point <numberType>::value )
392+ {
393+ this->data.value = std::move( value );
394+ this->data.isIncluded = isIncluded;
395+ }
396+ else
397+ {
398+#ifdef _MSC_VER
399+ static_assert( false, "invalid numberType in advanced lowerBound constructor" );
400+#endif //_MSC_VER
401+ }
402+ }
403+
404+ AINLINE lowerBound( const lowerBound& ) = default;
405+ AINLINE lowerBound( lowerBound&& ) = default;
406+
407+ AINLINE ~lowerBound( void ) = default;
408+
409+ AINLINE lowerBound& operator = ( const lowerBound& ) = default;
410+ AINLINE lowerBound& operator = ( lowerBound&& ) = default;
411+
412+ AINLINE void highbound( numberType bound, bool isIncluded = true ) noexcept(std::is_floating_point <numberType>::value)
413+ {
414+ if constexpr ( std::is_integral <numberType>::value )
415+ {
416+ if ( isIncluded == false )
417+ {
418+ if ( bound == std::numeric_limits <numberType>::max() )
419+ {
420+ // I decided against storing the "alwaysFalse" condition inside the bounds for
421+ // integral values because it is such a rare condition that should be prevented
422+ // by the slice user. Otherwise we would pollute many memory and other logic
423+ // classes!
424+ throw eir_exception();
425+ }
426+
427+ bound++;
428+ }
429+
430+ if ( bound > this->data.value )
431+ {
432+ this->data.value = bound;
433+ }
434+ }
435+ else if constexpr ( std::is_floating_point <numberType>::value )
436+ {
437+ numberType curBound = this->data.value;
438+
439+ if ( bound == curBound )
440+ {
441+ if ( isIncluded == false )
442+ {
443+ this->data.isIncluded = false;
444+ }
445+ }
446+ else if ( bound > curBound )
447+ {
448+ this->data.value = bound;
449+ this->data.isIncluded = isIncluded;
450+ }
451+ }
452+ else
453+ {
454+#ifdef _MSC_VER
455+ static_assert( false, "invalid numberType for lowerBound::highbound" );
456+#endif //_MSC_VER
457+ }
458+ }
459+
460+ // If we are a floating-point then our value is a number that converges very close to the actual value from infinity.
461+
462+ AINLINE friend bool operator <= ( const lowerBound& left, const lowerBound& right ) noexcept
463+ {
464+ if constexpr ( std::is_integral <numberType>::value )
465+ {
466+ return ( left.data.value <= right.data.value );
467+ }
468+ else if constexpr ( std::is_floating_point <numberType>::value )
469+ {
470+ bool isSameIncluded = ( left.data.isIncluded );
471+
472+ if ( isSameIncluded )
473+ {
474+ return ( left.data.value <= right.data.value );
475+ }
476+ else
477+ {
478+ return ( left.data.value < right.data.value );
479+ }
480+ }
481+ else
482+ {
483+ return false;
484+ }
485+ }
486+ AINLINE friend bool operator > ( const lowerBound& left, const lowerBound& right ) noexcept
487+ {
488+ return !( operator <= ( left, right ) );
489+ }
490+ AINLINE friend bool operator >= ( const lowerBound& left, const lowerBound& right ) noexcept
491+ {
492+ return operator <= ( right, left );
493+ }
494+ AINLINE friend bool operator < ( const lowerBound& left, const lowerBound& right ) noexcept
495+ {
496+ return !( operator >= ( left, right ) );
497+ }
498+
499+ // Equality implementation.
500+ AINLINE friend bool operator == ( const lowerBound& left, const lowerBound& right ) noexcept
501+ {
502+ if ( left.data.value != right.data.value )
503+ {
504+ return false;
505+ }
506+
507+ if constexpr ( std::is_floating_point <numberType>::value )
508+ {
509+ if ( left.data.isIncluded != right.data.isIncluded )
510+ {
511+ return false;
512+ }
513+ }
514+
515+ return true;
516+ }
517+ AINLINE friend bool operator != ( const lowerBound& left, const lowerBound& right ) noexcept
518+ {
519+ return !( operator == ( left, right ) );
520+ }
521+
522+ // Standard comparison with number.
523+ AINLINE bool is_bounded( const lowerBound& value ) const noexcept
524+ {
525+ return ( *this <= value );
526+ }
527+
528+ AINLINE const numberType& get_value( void ) const noexcept
529+ {
530+ return this->data.value;
531+ }
532+
533+ AINLINE bool is_included( void ) const noexcept
534+ {
535+ if constexpr ( std::is_integral <numberType>::value )
536+ {
537+ return true;
538+ }
539+ else if constexpr ( std::is_floating_point <numberType>::value )
540+ {
541+ return this->data.isIncluded;
542+ }
543+ else
544+ {
545+ return false;
546+ }
547+ }
548+
549+private:
550+ struct fields_integral
551+ {
552+ numberType value;
553+ };
554+
555+ struct fields_floating_point
556+ {
557+ numberType value;
558+ bool isIncluded;
559+ };
560+
561+ typename std::conditional <std::is_floating_point <numberType>::value, fields_floating_point, fields_integral>::type data;
562+};
563+
564+// *** Methods that work in combination of both lowerBound and upperBound.
565+
566+// Returns the difference between upper border and lower border of an interval.
567+template <typename numberType>
568+AINLINE numberType get_bound_span( const lowerBound <numberType>& low, const upperBound <numberType>& high ) noexcept
569+{
570+ if constexpr ( std::is_integral <numberType>::value )
571+ {
572+ if constexpr ( std::is_unsigned <numberType>::value )
573+ {
574+ numberType lowValue = low.get_value();
575+ numberType highValue = high.get_value();
576+
577+ // Remember that only highValue has a special case for max.
578+
579+ // Special case: treat max as -1.
580+ if ( highValue == std::numeric_limits <numberType>::max() )
581+ {
582+ // Really does not work.
583+ return 0;
584+ }
585+
586+ // Actually really cool that we can handle this case so gracefully.
587+
588+ if ( lowValue > highValue )
589+ {
590+ // Meow.
591+ return 0;
592+ }
593+
594+ return ( highValue - lowValue + 1 );
595+ }
596+ else
597+ {
598+ return ( high.get_value() - low.get_value() + 1 );
599+ }
600+ }
601+ else if constexpr ( std::is_floating_point <numberType>::value )
602+ {
603+ return ( high.get_value() - low.get_value() );
604+ }
605+ else
606+ {
607+#ifdef _MSC_VER
608+ static_assert( false, "invalid numberType in get_bound_span function" );
609+#endif //_MSC_VER
610+ }
611+}
612+
613+// Compares two bound spans and returns the status.
614+template <typename numberType>
615+AINLINE eCompResult compare_bounds( const lowerBound <numberType>& low, const upperBound <numberType>& high )
616+{
617+ if constexpr ( std::is_integral <numberType>::value )
618+ {
619+ if constexpr ( std::is_unsigned <numberType>::value )
620+ {
621+ numberType lowBound = low.get_value();
622+ numberType highBound = high.get_value();
623+
624+ // Special case: treat max as -1.
625+ if ( highBound == std::numeric_limits <numberType>::max() )
626+ {
627+ return eCompResult::LEFT_GREATER;
628+ }
629+
630+ return eir::DefaultValueCompare( lowBound, highBound );
631+ }
632+ else
633+ {
634+ return eir::DefaultValueCompare( low.get_value(), high.get_value() );
635+ }
636+ }
637+ else if constexpr ( std::is_floating_point <numberType>::value )
638+ {
639+ return eir::DefaultValueCompare( low.get_value(), high.get_value() );
640+ }
641+ else
642+ {
643+#ifdef _MSC_VER
644+ static_assert( false, "invalid numberType in compare_bounds function" );
645+#endif //_MSC_VER
646+ }
647+}
648+
649+// *** Operators between lowerBound and upperBound.
650+
651+template <typename numberType>
652+AINLINE bool operator <= ( const lowerBound <numberType>& left, const upperBound <numberType>& right ) noexcept
653+{
654+ bool isSameIncluded = ( left.is_included() && right.is_included() );
655+
656+ eCompResult cmpRes = compare_bounds( left, right );
657+
658+ if ( cmpRes == eCompResult::LEFT_GREATER )
659+ {
660+ return false;
661+ }
662+
663+ if ( isSameIncluded == false && cmpRes == eCompResult::EQUAL )
664+ {
665+ return false;
666+ }
667+
668+ return true;
669+}
670+template <typename numberType>
671+AINLINE bool operator > ( const lowerBound <numberType>& left, const upperBound <numberType>& right ) noexcept
672+{
673+ return !( operator <= ( left, right ) );
674+}
675+template <typename numberType>
676+AINLINE bool operator >= ( const upperBound <numberType>& left, const lowerBound <numberType>& right ) noexcept
677+{
678+ return operator <= ( right, left );
679+}
680+template <typename numberType>
681+AINLINE bool operator < ( const upperBound <numberType>& left, const lowerBound <numberType>& right ) noexcept
682+{
683+ return !( operator >= ( left, right ) );
684+}
685+
686+// *** Now the other way round, operators.
687+
688+template <typename numberType>
689+AINLINE bool operator <= ( const upperBound <numberType>& left, const lowerBound <numberType>& right ) noexcept
690+{
691+ bool isSameIncluded = ( left.is_included() && right.is_included() );
692+
693+ eCompResult cmpRes = compare_bounds( right, left );
694+
695+ if ( cmpRes == eCompResult::LEFT_LESS )
696+ {
697+ return false;
698+ }
699+
700+ if ( isSameIncluded == false && eCompResult::EQUAL )
701+ {
702+ return false;
703+ }
704+
705+ return true;
706+}
707+template <typename numberType>
708+AINLINE bool operator > ( const upperBound <numberType>& left, const lowerBound <numberType>& right ) noexcept
709+{
710+ return !( operator <= ( left, right ) );
711+}
712+template <typename numberType>
713+AINLINE bool operator < ( const lowerBound <numberType>& left, const upperBound <numberType>& right ) noexcept
714+{
715+ return operator > ( right, left );
716+}
717+template <typename numberType>
718+AINLINE bool operator >= ( const lowerBound <numberType>& left, const upperBound <numberType>& right ) noexcept
719+{
720+ return !( operator < ( left, right ) );
721+}
722+
723+enum eIntersectionResult
724+{
725+ INTERSECT_EQUAL,
726+ INTERSECT_INSIDE,
727+ INTERSECT_BORDER_START,
728+ INTERSECT_BORDER_END,
729+ INTERSECT_ENCLOSING,
730+ INTERSECT_FLOATING_START,
731+ INTERSECT_FLOATING_END,
732+ INTERSECT_UNKNOWN // if something went horribly wrong (like NaNs).
733+};
734+
735+// Static methods for easier result management.
736+AINLINE bool isBorderIntersect( eIntersectionResult result ) noexcept
737+{
738+ return ( result == INTERSECT_BORDER_START || result == INTERSECT_BORDER_END );
739+}
740+
741+AINLINE bool isFloatingIntersect( eIntersectionResult result ) noexcept
742+{
743+ return ( result == INTERSECT_FLOATING_START || result == INTERSECT_FLOATING_END );
744+}
745+
746+// Representation of a mathematical interval.
747+template <typename numberType>
748+class mathSlice
749+{
750+ AINLINE mathSlice( numberType startOffset, numberType endOffset, bool startIncluded, bool endIncluded ) noexcept
751+ : startBound( startOffset, startIncluded ), endBound( endOffset, endIncluded )
752+ {
753+ return;
754+ }
755+
756+public:
757+ AINLINE mathSlice( void ) noexcept : startBound( 0 ), endBound( 0, false )
758+ {
759+ return;
760+ }
761+
762+ AINLINE mathSlice( numberType startOffset, numberType dataSize ) noexcept : startBound( startOffset ), endBound( startOffset + dataSize, false )
763+ {
764+ return;
765+ }
766+
767+ // Note that both offsets are inclusive.
768+ static AINLINE mathSlice fromOffsets( numberType startOffset, numberType endOffset, bool startIncluded = true, bool endIncluded = true ) noexcept
769+ {
770+ return mathSlice( startOffset, endOffset, startIncluded, endIncluded );
771+ }
772+
773+ AINLINE bool IsEmpty( void ) const noexcept
774+ {
775+ return ( this->startBound > this->endBound );
776+ }
777+
778+ AINLINE numberType GetSliceSize( void ) const noexcept
779+ {
780+ return get_bound_span( this->startBound, this->endBound );
781+ }
782+
783+ AINLINE void SetSlicePosition( numberType val ) noexcept(noexcept(lowerBound(val)) && noexcept(upperBound(val, false)))
784+ {
785+ const numberType sliceSize = GetSliceSize();
786+
787+ this->startBound = lowerBound( val );
788+ this->endBound = upperBound( val + sliceSize, false );
789+ }
790+
791+ AINLINE void OffsetSliceBy( numberType val ) noexcept(noexcept(SetSlicePosition( val )))
792+ {
793+ SetSlicePosition( this->startBound.get_value() + val );
794+ }
795+
796+ AINLINE void SetSliceStartPoint( numberType val ) noexcept
797+ {
798+ this->startBound = lowerBound( val );
799+ }
800+
801+ AINLINE void SetSliceEndPoint( numberType val ) noexcept
802+ {
803+ this->endBound = upperBound( val );
804+ }
805+
806+ AINLINE numberType GetSliceStartPoint( void ) const noexcept
807+ {
808+ return startBound.get_value();
809+ }
810+
811+ AINLINE bool IsStartIncluded( void ) const noexcept
812+ {
813+ return startBound.is_included();
814+ }
815+
816+ AINLINE numberType GetSliceEndPoint( void ) const noexcept
817+ {
818+ return endBound.get_value();
819+ }
820+
821+ AINLINE bool IsEndIncluded( void ) const noexcept
822+ {
823+ return endBound.is_included();
824+ }
825+
826+ AINLINE void collapse( void ) noexcept
827+ {
828+ this->endBound = upperBound( this->startBound.get_value(), false );
829+ }
830+
831+ AINLINE eIntersectionResult intersectWith( const mathSlice& right ) const noexcept
832+ {
833+ // Make sure the slice has a valid size.
834+ if ( this->IsEmpty() == false )
835+ {
836+ // Get generic stuff.
837+ lowerBound <numberType> sliceStartA = this->startBound;
838+ upperBound <numberType> sliceEndA = this->endBound;
839+
840+ lowerBound <numberType> sliceStartB = right.startBound;
841+ upperBound <numberType> sliceEndB = right.endBound;
842+
843+ // slice A -> this
844+ // slice B -> right
845+
846+ // Handle all cases.
847+ // We implement the logic with comparisons only, as it is the most transparent for all number types.
848+ if ( sliceStartA == sliceStartB && sliceEndA == sliceEndB )
849+ {
850+ // Slice A is equal to Slice B
851+ return INTERSECT_EQUAL;
852+ }
853+
854+ if ( sliceStartB >= sliceStartA && sliceEndB <= sliceEndA )
855+ {
856+ // Slice A is enclosing Slice B
857+ return INTERSECT_ENCLOSING;
858+ }
859+
860+ if ( sliceStartB <= sliceStartA && sliceEndB >= sliceEndA )
861+ {
862+ // Slice A is inside Slice B
863+ return INTERSECT_INSIDE;
864+ }
865+
866+ if ( sliceStartB < sliceStartA && ( sliceEndB >= sliceStartA && sliceEndB <= sliceEndA ) )
867+ {
868+ // Slice A is being intersected at the starting point.
869+ return INTERSECT_BORDER_START;
870+ }
871+
872+ if ( sliceEndB > sliceEndA && ( sliceStartB >= sliceStartA && sliceStartB <= sliceEndA ) )
873+ {
874+ // Slice A is being intersected at the ending point.
875+ return INTERSECT_BORDER_END;
876+ }
877+
878+ if ( sliceStartB < sliceStartA && sliceEndB < sliceStartA )
879+ {
880+ // Slice A is after Slice B
881+ return INTERSECT_FLOATING_END;
882+ }
883+
884+ if ( sliceStartB > sliceEndA && sliceEndB > sliceEndA )
885+ {
886+ // Slice A is before Slice B
887+ return INTERSECT_FLOATING_START;
888+ }
889+ }
890+
891+ return INTERSECT_UNKNOWN;
892+ }
893+
894+ AINLINE bool getSharedRegion( const mathSlice& right, mathSlice& sharedOut ) const noexcept
895+ {
896+ eIntersectionResult intResult = this->intersectWith( right );
897+
898+ numberType startPos, endPos;
899+ bool startIncluded, endIncluded;
900+ bool hasPosition = false;
901+
902+ if ( intResult == INTERSECT_EQUAL || intResult == INTERSECT_ENCLOSING )
903+ {
904+ startPos = right.GetSliceStartPoint();
905+ endPos = right.GetSliceEndPoint();
906+
907+ startIncluded = right.IsStartIncluded();
908+ endIncluded = right.IsEndIncluded();
909+
910+ hasPosition = true;
911+ }
912+ else if ( intResult == INTERSECT_INSIDE )
913+ {
914+ startPos = this->GetSliceStartPoint();
915+ endPos = this->GetSliceEndPoint();
916+
917+ startIncluded = this->IsStartIncluded();
918+ endIncluded = this->IsEndIncluded();
919+
920+ hasPosition = true;
921+ }
922+ else if ( intResult == INTERSECT_BORDER_START )
923+ {
924+ startPos = this->GetSliceStartPoint();
925+ endPos = right.GetSliceEndPoint();
926+
927+ startIncluded = this->IsStartIncluded();
928+ endIncluded = right.IsEndIncluded();
929+
930+ hasPosition = true;
931+ }
932+ else if ( intResult == INTERSECT_BORDER_END )
933+ {
934+ startPos = right.GetSliceStartPoint();
935+ endPos = this->GetSliceEndPoint();
936+
937+ startIncluded = right.IsStartIncluded();
938+ endIncluded = this->IsEndIncluded();
939+
940+ hasPosition = true;
941+ }
942+ else if ( intResult == INTERSECT_FLOATING_START || intResult == INTERSECT_FLOATING_END )
943+ {
944+ // Nothing to do.
945+ }
946+ // we could also intersect unknown, in which case we do not care.
947+
948+ if ( hasPosition )
949+ {
950+ sharedOut = fromOffsets( startPos, endPos, startIncluded, endIncluded );
951+ }
952+
953+ return hasPosition;
954+ }
955+
956+ template <typename callbackType>
957+ AINLINE void subtractRegion( const mathSlice& subtractBy, const callbackType& cb ) const noexcept
958+ {
959+ // This method does only work for integers, for now.
960+
961+ // We return all memory data that is in our region but outside of subtractBy.
962+ lowerBound <numberType> ourStartBound = this->startBound;
963+ upperBound <numberType> ourEndBound = this->endBound;
964+
965+ if ( ourStartBound > ourEndBound )
966+ return;
967+
968+ lowerBound <numberType> subStartBound = subtractBy.startBound;
969+ upperBound <numberType> subEndBound = subtractBy.endBound;
970+
971+ // If the subtract region has nothing, then we just return our entire region.
972+ if ( subStartBound > subEndBound )
973+ {
974+ cb( *this, true );
975+ return;
976+ }
977+
978+ eIntersectionResult intResult = this->intersectWith( subtractBy );
979+
980+ if ( intResult == INTERSECT_FLOATING_START || intResult == INTERSECT_FLOATING_END )
981+ {
982+ // Since there is nothing subtracted, we can return the entire thing.
983+ cb( *this, true );
984+ }
985+ else if ( intResult == INTERSECT_BORDER_START )
986+ {
987+ // Just return the remainder.
988+ const mathSlice remainder = fromOffsets( subEndBound.get_value(), ourEndBound.get_value(), !subEndBound.is_included(), ourEndBound.is_included() );
989+
990+ cb( remainder, false );
991+ }
992+ else if ( intResult == INTERSECT_BORDER_END )
993+ {
994+ const mathSlice remainder = fromOffsets( ourStartBound.get_value(), subStartBound.get_value(), ourStartBound.is_included(), !subStartBound.is_included() );
995+
996+ cb( remainder, true );
997+ }
998+ else if ( intResult == INTERSECT_ENCLOSING )
999+ {
1000+ // Since we are enclosing the subtractBy, we could have both region before and region after subtractBy.
1001+ if ( ourStartBound < subStartBound )
1002+ {
1003+ mathSlice leftRegion = fromOffsets( ourStartBound.get_value(), subStartBound.get_value(), ourStartBound.is_included(), !subStartBound.is_included() );
1004+
1005+ cb( leftRegion, true );
1006+ }
1007+
1008+ if ( ourEndBound > subEndBound )
1009+ {
1010+ mathSlice rightRegion = fromOffsets( subEndBound.get_value(), ourEndBound.get_value(), !subEndBound.is_included(), ourEndBound.is_included() );
1011+
1012+ cb( rightRegion, false );
1013+ }
1014+ }
1015+ else if ( intResult == INTERSECT_INSIDE ||
1016+ intResult == INTERSECT_EQUAL )
1017+ {
1018+ // We have been entirely overshadowed/removed by subtractBy.
1019+ }
1020+ else if ( intResult == INTERSECT_UNKNOWN )
1021+ {
1022+ // Could be caused by some hardware math fault, we just return the entire thing.
1023+ cb( *this, true );
1024+ }
1025+ }
1026+
1027+private:
1028+ lowerBound <numberType> startBound;
1029+ upperBound <numberType> endBound;
1030+};
1031+
1032+// Neighborhood function.
1033+template <typename leftNumberType, typename rightNumberType>
1034+AINLINE bool IsNumberInNeighborhood( const leftNumberType& left, const rightNumberType& right )
1035+{
1036+ if constexpr ( std::is_floating_point <leftNumberType>::value || std::is_floating_point <rightNumberType>::value )
1037+ {
1038+ return ( left == right );
1039+ }
1040+
1041+ if ( std::is_integral <leftNumberType>::value && std::is_integral <rightNumberType>::value )
1042+ {
1043+ if ( left == right )
1044+ {
1045+ return true;
1046+ }
1047+
1048+ if ( left > std::numeric_limits <leftNumberType>::min() )
1049+ {
1050+ if ( left - 1 == right )
1051+ {
1052+ return true;
1053+ }
1054+ }
1055+
1056+ if ( left < std::numeric_limits <leftNumberType>::max() )
1057+ {
1058+ if ( left + 1 == right )
1059+ {
1060+ return true;
1061+ }
1062+ }
1063+ }
1064+
1065+ return false;
1066+}
1067+
1068+} //namespace eir
1069+
1070+#endif //_EIR_SDK_MATH_SLICE_HEADER_
\ No newline at end of file
--- common/sdk/MemoryRaw.h (revision 170)
+++ common/sdk/MemoryRaw.h (revision 171)
@@ -13,308 +13,14 @@
1313 #ifndef _MEMORY_RAW_DEFS_
1414 #define _MEMORY_RAW_DEFS_
1515
16-#include <type_traits>
17-#include <limits>
16+#include "MathSlice.h"
1817
19-#include "MacroUtils.h"
20-
2118 // Mathematically correct data slice logic.
2219 // It is one of the most important theorems in computing abstraction.
20+// TODO: limit this type to integral things only.
2321 template <typename numberType>
24-class sliceOfData
25-{
26- AINLINE sliceOfData( numberType startOffset, numberType endOffset, unsigned int _ ) noexcept
27- {
28- this->startOffset = startOffset;
29- this->endOffset = endOffset;
30- }
22+using sliceOfData = eir::mathSlice <numberType>;
3123
32-public:
33- AINLINE sliceOfData( void ) noexcept
34- {
35- this->startOffset = 0;
36- this->endOffset = -1;
37- }
38-
39- AINLINE sliceOfData( numberType startOffset, numberType dataSize ) noexcept
40- {
41- this->startOffset = startOffset;
42- this->endOffset = startOffset + ( dataSize - 1 );
43- }
44-
45- // Note that both offsets are inclusive.
46- static AINLINE sliceOfData fromOffsets( numberType startOffset, numberType endOffset ) noexcept
47- {
48- return sliceOfData( startOffset, endOffset, 0 );
49- }
50-
51- enum eIntersectionResult
52- {
53- INTERSECT_EQUAL,
54- INTERSECT_INSIDE,
55- INTERSECT_BORDER_START,
56- INTERSECT_BORDER_END,
57- INTERSECT_ENCLOSING,
58- INTERSECT_FLOATING_START,
59- INTERSECT_FLOATING_END,
60- INTERSECT_UNKNOWN // if something went horribly wrong (like NaNs).
61- };
62-
63- // Static methods for easier result management.
64- static AINLINE bool isBorderIntersect( eIntersectionResult result ) noexcept
65- {
66- return ( result == INTERSECT_BORDER_START || result == INTERSECT_BORDER_END );
67- }
68-
69- static AINLINE bool isFloatingIntersect( eIntersectionResult result ) noexcept
70- {
71- return ( result == INTERSECT_FLOATING_START || result == INTERSECT_FLOATING_END );
72- }
73-
74- AINLINE bool IsEmpty( void ) const noexcept
75- {
76- // Very special stance.
77- // Works for integers only.
78- if ( this->startOffset == 0 && this->endOffset == -1 )
79- {
80- return true;
81- }
82-
83- return ( this->endOffset < this->startOffset );
84- }
85-
86- AINLINE numberType GetSliceSize( void ) const noexcept
87- {
88- return ( this->endOffset - this->startOffset ) + 1;
89- }
90-
91- AINLINE void SetSlicePosition( numberType val ) noexcept
92- {
93- const numberType sliceSize = GetSliceSize();
94-
95- this->startOffset = val;
96- this->endOffset = val + ( sliceSize - 1 );
97- }
98-
99- AINLINE void OffsetSliceBy( numberType val ) noexcept
100- {
101- SetSlicePosition( this->startOffset + val );
102- }
103-
104- AINLINE void SetSliceStartPoint( numberType val ) noexcept
105- {
106- this->startOffset = val;
107- }
108-
109- AINLINE void SetSliceEndPoint( numberType val ) noexcept
110- {
111- this->endOffset = val;
112- }
113-
114- AINLINE numberType GetSliceStartPoint( void ) const noexcept
115- {
116- return startOffset;
117- }
118-
119- AINLINE numberType GetSliceEndPoint( void ) const noexcept
120- {
121- return endOffset;
122- }
123-
124- AINLINE void collapse( void ) noexcept
125- {
126- this->endOffset = ( this->startOffset - 1 );
127- }
128-
129- AINLINE eIntersectionResult intersectWith( const sliceOfData& right ) const noexcept
130- {
131- // Make sure the slice has a valid size.
132- if ( this->endOffset >= this->startOffset &&
133- right.endOffset >= right.startOffset )
134- {
135- // Get generic stuff.
136- numberType sliceStartA = startOffset, sliceEndA = endOffset;
137- numberType sliceStartB = right.startOffset, sliceEndB = right.endOffset;
138-
139- // slice A -> this
140- // slice B -> right
141-
142- // Handle all cases.
143- // We implement the logic with comparisons only, as it is the most transparent for all number types.
144- if ( sliceStartA == sliceStartB && sliceEndA == sliceEndB )
145- {
146- // Slice A is equal to Slice B
147- return INTERSECT_EQUAL;
148- }
149-
150- if ( sliceStartB >= sliceStartA && sliceEndB <= sliceEndA )
151- {
152- // Slice A is enclosing Slice B
153- return INTERSECT_ENCLOSING;
154- }
155-
156- if ( sliceStartB <= sliceStartA && sliceEndB >= sliceEndA )
157- {
158- // Slice A is inside Slice B
159- return INTERSECT_INSIDE;
160- }
161-
162- if ( sliceStartB < sliceStartA && ( sliceEndB >= sliceStartA && sliceEndB <= sliceEndA ) )
163- {
164- // Slice A is being intersected at the starting point.
165- return INTERSECT_BORDER_START;
166- }
167-
168- if ( sliceEndB > sliceEndA && ( sliceStartB >= sliceStartA && sliceStartB <= sliceEndA ) )
169- {
170- // Slice A is being intersected at the ending point.
171- return INTERSECT_BORDER_END;
172- }
173-
174- if ( sliceStartB < sliceStartA && sliceEndB < sliceStartA )
175- {
176- // Slice A is after Slice B
177- return INTERSECT_FLOATING_END;
178- }
179-
180- if ( sliceStartB > sliceEndA && sliceEndB > sliceEndA )
181- {
182- // Slice A is before Slice B
183- return INTERSECT_FLOATING_START;
184- }
185- }
186-
187- return INTERSECT_UNKNOWN;
188- }
189-
190- AINLINE bool getSharedRegion( const sliceOfData& right, sliceOfData& sharedOut ) const noexcept
191- {
192- eIntersectionResult intResult = this->intersectWith( right );
193-
194- numberType startPos, endPos;
195- bool hasPosition = false;
196-
197- if ( intResult == INTERSECT_EQUAL || intResult == INTERSECT_ENCLOSING )
198- {
199- startPos = right.GetSliceStartPoint();
200- endPos = right.GetSliceEndPoint();
201-
202- hasPosition = true;
203- }
204- else if ( intResult == INTERSECT_INSIDE )
205- {
206- startPos = this->GetSliceStartPoint();
207- endPos = this->GetSliceEndPoint();
208-
209- hasPosition = true;
210- }
211- else if ( intResult == INTERSECT_BORDER_START )
212- {
213- startPos = this->GetSliceStartPoint();
214- endPos = right.GetSliceEndPoint();
215-
216- hasPosition = true;
217- }
218- else if ( intResult == INTERSECT_BORDER_END )
219- {
220- startPos = right.GetSliceStartPoint();
221- endPos = this->GetSliceEndPoint();
222-
223- hasPosition = true;
224- }
225- else if ( intResult == INTERSECT_FLOATING_START || intResult == INTERSECT_FLOATING_END )
226- {
227- // Nothing to do.
228- }
229- // we could also intersect unknown, in which case we do not care.
230-
231- if ( hasPosition )
232- {
233- sharedOut = fromOffsets( startPos, endPos );
234- }
235-
236- return hasPosition;
237- }
238-
239- template <typename callbackType>
240- AINLINE void subtractRegion( const sliceOfData& subtractBy, const callbackType& cb ) const noexcept
241- {
242- // This method does only work for integers, for now.
243-
244- // We return all memory data that is in our region but outside of subtractBy.
245- numberType ourStartOffset = this->startOffset;
246- numberType ourEndOffset = this->endOffset;
247-
248- if ( ourStartOffset > ourEndOffset )
249- return;
250-
251- numberType subStartOffset = subtractBy.startOffset;
252- numberType subEndOffset = subtractBy.endOffset;
253-
254- // If the subtract region has nothing, then we just return our entire region.
255- if ( subStartOffset > subEndOffset )
256- {
257- const sliceOfData region = *this;
258-
259- cb( region, true );
260- return;
261- }
262-
263- eIntersectionResult intResult = this->intersectWith( subtractBy );
264-
265- if ( intResult == INTERSECT_FLOATING_START || intResult == INTERSECT_FLOATING_END )
266- {
267- // Since there is nothing subtracted, we can return the entire thing.
268- cb( *this, true );
269- }
270- else if ( intResult == INTERSECT_BORDER_START )
271- {
272- // Just return the remainder.
273- numberType oneAfterSubEndOffset = ( subEndOffset + 1 );
274- const sliceOfData remainder( oneAfterSubEndOffset, ourEndOffset - oneAfterSubEndOffset );
275-
276- cb( remainder, false );
277- }
278- else if ( intResult == INTERSECT_BORDER_END )
279- {
280- const sliceOfData remainder( ourStartOffset, subStartOffset - ourStartOffset );
281-
282- cb( remainder, true );
283- }
284- else if ( intResult == INTERSECT_ENCLOSING )
285- {
286- // Since we are enclosing the subtractBy, we could have both region before and region after subtractBy.
287- if ( ourStartOffset < subStartOffset )
288- {
289- sliceOfData leftRegion( ourStartOffset, subStartOffset - ourStartOffset );
290-
291- cb( leftRegion, true );
292- }
293-
294- if ( ourEndOffset > subEndOffset )
295- {
296- sliceOfData rightRegion = fromOffsets( subEndOffset + 1, ourEndOffset );
297-
298- cb( rightRegion, false );
299- }
300- }
301- else if ( intResult == INTERSECT_INSIDE ||
302- intResult == INTERSECT_EQUAL )
303- {
304- // We have been entirely overshadowed/removed by subtractBy.
305- }
306- else if ( intResult == INTERSECT_UNKNOWN )
307- {
308- // Could be caused by some hardware math fault, we just return the entire thing.
309- cb( *this, true );
310- }
311- }
312-
313-private:
314- numberType startOffset;
315- numberType endOffset;
316-};
317-
31824 #include <bitset>
31925
32026 // Macro that defines how alignment works.
@@ -375,40 +81,4 @@
37581 return ( ALIGN( (num), (sector), (sector) ) );
37682 }
37783
378-// Neighborhood function.
379-template <typename leftNumberType, typename rightNumberType>
380-AINLINE bool IsNumberInNeighborhood( const leftNumberType& left, const rightNumberType& right )
381-{
382- if constexpr ( std::is_floating_point <leftNumberType>::value || std::is_floating_point <rightNumberType>::value )
383- {
384- return ( left == right );
385- }
386-
387- if ( std::is_integral <leftNumberType>::value && std::is_integral <rightNumberType>::value )
388- {
389- if ( left == right )
390- {
391- return true;
392- }
393-
394- if ( left > std::numeric_limits <leftNumberType>::min() )
395- {
396- if ( left - 1 == right )
397- {
398- return true;
399- }
400- }
401-
402- if ( left < std::numeric_limits <leftNumberType>::max() )
403- {
404- if ( left + 1 == right )
405- {
406- return true;
407- }
408- }
409- }
410-
411- return false;
412-}
413-
41484 #endif //_MEMORY_RAW_DEFS_
\ No newline at end of file
--- common/sdk/MemoryUtils.h (revision 170)
+++ common/sdk/MemoryUtils.h (revision 171)
@@ -81,9 +81,9 @@
8181 // Intersect the current memory slice with the ones on our list.
8282 memSlice_t blockSlice = iter.GetMemorySlice();
8383
84- typename memSlice_t::eIntersectionResult intResult = finalAllocSlice.intersectWith( blockSlice );
84+ typename eir::eIntersectionResult intResult = finalAllocSlice.intersectWith( blockSlice );
8585
86- if ( !memSlice_t::isFloatingIntersect( intResult ) )
86+ if ( !eir::isFloatingIntersect( intResult ) )
8787 {
8888 // Advance the try memory offset.
8989 numberType tryMemPosition = ( blockSlice.GetSliceEndPoint() + 1 );
@@ -95,7 +95,7 @@
9595 // Construct the new alloc slice.
9696 finalAllocSlice = memSlice_t( tryMemPosition, memOffsetSize );
9797 }
98- else if ( intResult == memSlice_t::INTERSECT_FLOATING_END )
98+ else if ( intResult == eir::INTERSECT_FLOATING_END )
9999 {
100100 // We kinda encounter this when the alignment makes us skip (!) over
101101 // data units.
@@ -167,7 +167,7 @@
167167
168168 blockIter_t appendNode = manager.GetRootNode();
169169
170- typename memSlice_t::eIntersectionResult nextIntResult = memSlice_t::INTERSECT_UNKNOWN;
170+ typename eir::eIntersectionResult nextIntResult = eir::INTERSECT_UNKNOWN;
171171 bool hasNextIntersection = false;
172172
173173 for ( blockIter_t iter( manager.GetFirstMemoryBlock() ); manager.IsEndMemoryBlock( iter ) == false; iter.Increment() )
@@ -175,9 +175,9 @@
175175 // We are interested in how many blocks we actually have to skip.
176176 const memSlice_t& blockSlice = iter.GetMemorySlice();
177177
178- typename memSlice_t::eIntersectionResult intResult = blockSlice.intersectWith( newAllocSlice );
178+ typename eir::eIntersectionResult intResult = blockSlice.intersectWith( newAllocSlice );
179179
180- if ( intResult != memSlice_t::INTERSECT_FLOATING_START )
180+ if ( intResult != eir::INTERSECT_FLOATING_START )
181181 {
182182 nextIntResult = intResult;
183183 hasNextIntersection = true;
@@ -189,7 +189,7 @@
189189 }
190190
191191 // If we have any kind of next node, and it intersects violently, then we have no space :(
192- if ( hasNextIntersection && nextIntResult != memSlice_t::INTERSECT_FLOATING_END )
192+ if ( hasNextIntersection && nextIntResult != eir::INTERSECT_FLOATING_END )
193193 {
194194 // There is a collision, meow.
195195 return false;
@@ -824,10 +824,10 @@
824824
825825 // Make sure we allocate in the valid region.
826826 {
827- memSlice_t::eIntersectionResult intResult = allocInfo.slice.intersectWith( validAllocationRegion );
827+ eir::eIntersectionResult intResult = allocInfo.slice.intersectWith( validAllocationRegion );
828828
829- if ( intResult != memSlice_t::INTERSECT_EQUAL &&
830- intResult != memSlice_t::INTERSECT_INSIDE )
829+ if ( intResult != eir::INTERSECT_EQUAL &&
830+ intResult != eir::INTERSECT_INSIDE )
831831 {
832832 return nullptr;
833833 }
--- common/sdk/MemoryUtils.stream.h (revision 170)
+++ common/sdk/MemoryUtils.stream.h (revision 171)
@@ -64,7 +64,7 @@
6464 streamSlice_t writeSlice( currentSeekOffset, seekWriteCount );
6565
6666 // We can only write as much as there is space available.
67- typename streamSlice_t::eIntersectionResult intResult;
67+ eir::eIntersectionResult intResult;
6868
6969 if ( streamSize != 0 )
7070 {
@@ -74,11 +74,11 @@
7474 }
7575
7676 if ( streamSize != 0 &&
77- intResult != streamSlice_t::INTERSECT_EQUAL &&
78- intResult != streamSlice_t::INTERSECT_INSIDE &&
79- intResult != streamSlice_t::INTERSECT_BORDER_START &&
80- intResult != streamSlice_t::INTERSECT_FLOATING_END &&
81- intResult != streamSlice_t::INTERSECT_ENCLOSING )
77+ intResult != eir::INTERSECT_EQUAL &&
78+ intResult != eir::INTERSECT_INSIDE &&
79+ intResult != eir::INTERSECT_BORDER_START &&
80+ intResult != eir::INTERSECT_FLOATING_END &&
81+ intResult != eir::INTERSECT_ENCLOSING )
8282 {
8383 // All other intersections do not produce a valid write access.
8484 return 0;
@@ -90,11 +90,11 @@
9090 size_t possibleWriteCount = 0;
9191
9292 if ( streamSize == 0 ||
93- intResult == streamSlice_t::INTERSECT_BORDER_START ||
94- intResult == streamSlice_t::INTERSECT_FLOATING_END ||
95- intResult == streamSlice_t::INTERSECT_ENCLOSING )
93+ intResult == eir::INTERSECT_BORDER_START ||
94+ intResult == eir::INTERSECT_FLOATING_END ||
95+ intResult == eir::INTERSECT_ENCLOSING )
9696 {
97- if ( streamSize != 0 && intResult == streamSlice_t::INTERSECT_ENCLOSING && currentSeekOffset < 0 )
97+ if ( streamSize != 0 && intResult == eir::INTERSECT_ENCLOSING && currentSeekOffset < 0 )
9898 {
9999 // We cannot write if our startpoint is invalid.
100100 return 0;
@@ -117,11 +117,11 @@
117117 // If possible, check if operation can be done, and how much.
118118 streamSlice_t newFileBound( 0, streamSize );
119119
120- typename streamSlice_t::eIntersectionResult newIntResult = writeSlice.intersectWith( newFileBound );
120+ eir::eIntersectionResult newIntResult = writeSlice.intersectWith( newFileBound );
121121
122- if ( newIntResult != streamSlice_t::INTERSECT_EQUAL &&
123- newIntResult != streamSlice_t::INTERSECT_INSIDE &&
124- newIntResult != streamSlice_t::INTERSECT_BORDER_START )
122+ if ( newIntResult != eir::INTERSECT_EQUAL &&
123+ newIntResult != eir::INTERSECT_INSIDE &&
124+ newIntResult != eir::INTERSECT_BORDER_START )
125125 {
126126 // We just cannot.
127127 return 0;
@@ -154,12 +154,12 @@
154154
155155 streamSlice_t boundSlice( 0, streamSize );
156156
157- typename streamSlice_t::eIntersectionResult intResult = readSlice.intersectWith( boundSlice );
157+ eir::eIntersectionResult intResult = readSlice.intersectWith( boundSlice );
158158
159- if ( intResult != streamSlice_t::INTERSECT_EQUAL &&
160- intResult != streamSlice_t::INTERSECT_INSIDE &&
161- intResult != streamSlice_t::INTERSECT_BORDER_START &&
162- intResult != streamSlice_t::INTERSECT_ENCLOSING )
159+ if ( intResult != eir::INTERSECT_EQUAL &&
160+ intResult != eir::INTERSECT_INSIDE &&
161+ intResult != eir::INTERSECT_BORDER_START &&
162+ intResult != eir::INTERSECT_ENCLOSING )
163163 {
164164 // We can only read valid data.
165165 return 0;
@@ -168,10 +168,10 @@
168168 // Determine how much we can read.
169169 size_t readable;
170170
171- if ( intResult == streamSlice_t::INTERSECT_BORDER_START ||
172- intResult == streamSlice_t::INTERSECT_ENCLOSING )
171+ if ( intResult == eir::INTERSECT_BORDER_START ||
172+ intResult == eir::INTERSECT_ENCLOSING )
173173 {
174- if ( intResult == streamSlice_t::INTERSECT_ENCLOSING && currentSeekOffset < 0 )
174+ if ( intResult == eir::INTERSECT_ENCLOSING && currentSeekOffset < 0 )
175175 {
176176 // Cannot read if our startpoint is invalid.
177177 return 0;
--- common/sdk/OSUtils.arrvmem.h (revision 170)
+++ common/sdk/OSUtils.arrvmem.h (revision 171)
@@ -170,10 +170,10 @@
170170
171171 memSlice_t arrayDataSlice = item->GetDataBounds();
172172
173- memSlice_t::eIntersectionResult intResult = itemSlice.intersectWith( arrayDataSlice );
173+ eir::eIntersectionResult intResult = itemSlice.intersectWith( arrayDataSlice );
174174
175- if ( intResult == memSlice_t::INTERSECT_EQUAL ||
176- intResult == memSlice_t::INTERSECT_INSIDE )
175+ if ( intResult == eir::INTERSECT_EQUAL ||
176+ intResult == eir::INTERSECT_INSIDE )
177177 {
178178 // We found it.
179179 residingSlice = std::move( arrayDataSlice );
--- common/sdk/OSUtils.h (revision 170)
+++ common/sdk/OSUtils.h (revision 171)
@@ -271,12 +271,12 @@
271271 pageHandle *curHandle = LIST_GETITEM( pageHandle, node, managerNode );
272272 pageAllocation *arenaHandle = this->arenaHandle;
273273
274- memBlockSlice_t::eIntersectionResult intResult =
274+ eir::eIntersectionResult intResult =
275275 curHandle->requestedMemory.intersectWith( arenaHandle->pageSpan );
276276
277- assert( intResult != memBlockSlice_t::INTERSECT_FLOATING_START );
277+ assert( intResult != eir::INTERSECT_FLOATING_START );
278278
279- return ( intResult == memBlockSlice_t::INTERSECT_FLOATING_END );
279+ return ( intResult == eir::INTERSECT_FLOATING_END );
280280 }
281281
282282 AINLINE void Increment( void )
@@ -325,9 +325,9 @@
325325 {
326326 static AINLINE void ProcessEntry( pageHandle *foreignHandle, size_t sortedIndex, const memBlockSlice_t& memoryRegion )
327327 {
328- memBlockSlice_t::eIntersectionResult intRes = foreignHandle->requestedMemory.intersectWith( memoryRegion );
328+ eir::eIntersectionResult intRes = foreignHandle->requestedMemory.intersectWith( memoryRegion );
329329
330- if ( memBlockSlice_t::isFloatingIntersect( intRes ) == false )
330+ if ( eir::isFloatingIntersect( intRes ) == false )
331331 {
332332 // Oh no :(
333333 __debugbreak();
@@ -461,11 +461,11 @@
461461 while ( node != &this->sortedMemoryRanges.root )
462462 {
463463 // The first arena that is floating after the page handle is the end marker.
464- memBlockSlice_t::eIntersectionResult intResult = curArena->pageSpan.intersectWith( arenaResident->requestedMemory );
464+ eir::eIntersectionResult intResult = curArena->pageSpan.intersectWith( arenaResident->requestedMemory );
465465
466- assert( intResult != memBlockSlice_t::INTERSECT_FLOATING_START );
466+ assert( intResult != eir::INTERSECT_FLOATING_START );
467467
468- if ( intResult == memBlockSlice_t::INTERSECT_FLOATING_END )
468+ if ( intResult == eir::INTERSECT_FLOATING_END )
469469 {
470470 // End marker.
471471 break;
@@ -588,7 +588,7 @@
588588
589589 arenaSortedIterator_t iter( this->sortedMemoryRanges );
590590
591- memBlockSlice_t::eIntersectionResult intResult;
591+ eir::eIntersectionResult intResult;
592592
593593 while ( !iter.IsEnd() )
594594 {
@@ -596,15 +596,15 @@
596596
597597 intResult = hostMem.intersectWith( curRegion->pageSpan );
598598
599- if ( intResult == memBlockSlice_t::INTERSECT_BORDER_START ||
600- intResult == memBlockSlice_t::INTERSECT_INSIDE ||
601- intResult == memBlockSlice_t::INTERSECT_EQUAL )
599+ if ( intResult == eir::INTERSECT_BORDER_START ||
600+ intResult == eir::INTERSECT_INSIDE ||
601+ intResult == eir::INTERSECT_EQUAL )
602602 {
603603 isHostingOut = true;
604604 isBeforeItOut = false;
605605 return curRegion;
606606 }
607- if ( intResult == memBlockSlice_t::INTERSECT_ENCLOSING )
607+ if ( intResult == eir::INTERSECT_ENCLOSING )
608608 {
609609 // If the start points match, then we are hosting.
610610 // Otherwise we cannot host it.
@@ -621,8 +621,8 @@
621621
622622 return curRegion;
623623 }
624- if ( intResult == memBlockSlice_t::INTERSECT_FLOATING_START ||
625- intResult == memBlockSlice_t::INTERSECT_BORDER_END )
624+ if ( intResult == eir::INTERSECT_FLOATING_START ||
625+ intResult == eir::INTERSECT_BORDER_END )
626626 {
627627 isHostingOut = false;
628628 isBeforeItOut = true;
@@ -632,7 +632,7 @@
632632 iter.Increment();
633633 }
634634
635- if ( curRegion && intResult == memBlockSlice_t::INTERSECT_FLOATING_END )
635+ if ( curRegion && intResult == eir::INTERSECT_FLOATING_END )
636636 {
637637 isHostingOut = false;
638638 isBeforeItOut = false;
@@ -812,13 +812,13 @@
812812
813813 if ( theEndingBit )
814814 {
815- memBlockSlice_t::eIntersectionResult endIntResult = handleAllocRegion.intersectWith( theEndingBit->pageSpan );
815+ eir::eIntersectionResult endIntResult = handleAllocRegion.intersectWith( theEndingBit->pageSpan );
816816
817- if ( endIntResult == memBlockSlice_t::INTERSECT_BORDER_END )
817+ if ( endIntResult == eir::INTERSECT_BORDER_END )
818818 {
819819 reqAllocEndBit = theEndingBit;
820820 }
821- else if ( endIntResult == memBlockSlice_t::INTERSECT_FLOATING_START )
821+ else if ( endIntResult == eir::INTERSECT_FLOATING_START )
822822 {
823823 // Nothing :)
824824 }
@@ -845,9 +845,9 @@
845845
846846 assert( firstAlloc != nullptr );
847847
848- memBlockSlice_t::eIntersectionResult intResult = handleAllocRegion.intersectWith( firstAlloc->requestedMemory );
848+ eir::eIntersectionResult intResult = handleAllocRegion.intersectWith( firstAlloc->requestedMemory );
849849
850- isObstructed = ( memBlockSlice_t::isFloatingIntersect( intResult ) == false );
850+ isObstructed = ( eir::isFloatingIntersect( intResult ) == false );
851851 }
852852
853853 if ( isObstructed )
@@ -969,9 +969,9 @@
969969 #ifdef _DEBUG
970970 {
971971 // Handle alloc region (page memory space) must be inside or equal to host alloc region (reserve memory space).
972- memBlockSlice_t::eIntersectionResult intResult = handleAllocRegion.intersectWith( hostAllocRegion );
972+ eir::eIntersectionResult intResult = handleAllocRegion.intersectWith( hostAllocRegion );
973973
974- assert( intResult == memBlockSlice_t::INTERSECT_INSIDE || intResult == memBlockSlice_t::INTERSECT_EQUAL );
974+ assert( intResult == eir::INTERSECT_INSIDE || intResult == eir::INTERSECT_EQUAL );
975975 }
976976 #endif //_DEBUG
977977
@@ -984,9 +984,9 @@
984984 arenaSortedIterator_t reserveArenaIter( this->sortedMemoryRanges, &hostStartRegion->sortedNode );
985985
986986 // Check if the starting region is even relevant.
987- memBlockSlice_t::eIntersectionResult intResult = handleAllocRegion.intersectWith( hostStartRegion->pageSpan );
987+ eir::eIntersectionResult intResult = handleAllocRegion.intersectWith( hostStartRegion->pageSpan );
988988
989- assert( memBlockSlice_t::isFloatingIntersect( intResult ) == false );
989+ assert( eir::isFloatingIntersect( intResult ) == false );
990990 {
991991 // Add the starting region as allocate-at.
992992 memReserveAllocInfo info;
@@ -1017,9 +1017,9 @@
10171017 // We assume that this is always the case.
10181018 #ifdef _DEBUG
10191019 {
1020- memBlockSlice_t::eIntersectionResult intResult = memRegion.intersectWith( arenaHandle->pageSpan );
1020+ eir::eIntersectionResult intResult = memRegion.intersectWith( arenaHandle->pageSpan );
10211021
1022- assert( memBlockSlice_t::isFloatingIntersect( intResult ) == false );
1022+ assert( eir::isFloatingIntersect( intResult ) == false );
10231023 }
10241024 #endif //_DEBUG
10251025
@@ -1032,15 +1032,15 @@
10321032 pageHandle *alloc = iter.Resolve();
10331033
10341034 // Check what to make of this.
1035- memBlockSlice_t::eIntersectionResult intResult = memRegion.intersectWith( alloc->requestedMemory );
1035+ eir::eIntersectionResult intResult = memRegion.intersectWith( alloc->requestedMemory );
10361036
1037- if ( intResult == memBlockSlice_t::INTERSECT_FLOATING_START )
1037+ if ( intResult == eir::INTERSECT_FLOATING_START )
10381038 {
10391039 // Our requested memory does not conflict with anything and is prior to the current thing.
10401040 isFirstOut = isFirst;
10411041 return true;
10421042 }
1043- if ( intResult == memBlockSlice_t::INTERSECT_FLOATING_END )
1043+ if ( intResult == eir::INTERSECT_FLOATING_END )
10441044 {
10451045 // We can continue ahead.
10461046 }
@@ -1066,9 +1066,9 @@
10661066 // Check if we are obstructed by the (next) resident memory.
10671067 // This does not guarrentee allocability on its own, but it gives us a good idea.
10681068
1069- memBlockSlice_t::eIntersectionResult intResult = handleAllocSlice.intersectWith( obstructAlloc->requestedMemory );
1069+ eir::eIntersectionResult intResult = handleAllocSlice.intersectWith( obstructAlloc->requestedMemory );
10701070
1071- return ( memBlockSlice_t::isFloatingIntersect( intResult ) == false );
1071+ return ( eir::isFloatingIntersect( intResult ) == false );
10721072 }
10731073
10741074 // Try placement of memory allocation on a specific memory address.
@@ -1216,12 +1216,12 @@
12161216
12171217 // Is the selected allocation spot available?
12181218 // We skip any memory blocks entirely before the handle region.
1219- memBlockSlice_t::eIntersectionResult intResult =
1219+ eir::eIntersectionResult intResult =
12201220 obstructAlloc->requestedMemory.intersectWith( handleAllocSlice );
12211221
1222- if ( intResult != memBlockSlice_t::INTERSECT_FLOATING_START )
1222+ if ( intResult != eir::INTERSECT_FLOATING_START )
12231223 {
1224- isCurrentAllocationSpotObstructed = ( intResult != memBlockSlice_t::INTERSECT_FLOATING_END );
1224+ isCurrentAllocationSpotObstructed = ( intResult != eir::INTERSECT_FLOATING_END );
12251225 break;
12261226 }
12271227
@@ -1343,10 +1343,10 @@
13431343 // The page handle will be normalízed on loop beginning.
13441344 while ( true )
13451345 {
1346- memBlockSlice_t::eIntersectionResult intResult =
1346+ eir::eIntersectionResult intResult =
13471347 currentArena->pageSpan.intersectWith( handleAllocSlice );
13481348
1349- if ( intResult != memBlockSlice_t::INTERSECT_FLOATING_START )
1349+ if ( intResult != eir::INTERSECT_FLOATING_START )
13501350 {
13511351 // There is an intersection, so we are ok.
13521352 break;
@@ -1494,7 +1494,7 @@
14941494 // Since we assume that the handle we found is pretty close to being sorted, we just go to
14951495 // the neighbors until we found the correct spot.
14961496
1497- memBlockSlice_t::eIntersectionResult beg_intResult =
1497+ eir::eIntersectionResult beg_intResult =
14981498 prettyCloseHandle->requestedMemory.intersectWith( desiredMemSlice );
14991499
15001500 // Check if the close handle is left or right from our memory.
@@ -1503,12 +1503,12 @@
15031503
15041504 bool leftTrueRightFalse = false;
15051505
1506- if ( beg_intResult == memBlockSlice_t::INTERSECT_FLOATING_START )
1506+ if ( beg_intResult == eir::INTERSECT_FLOATING_START )
15071507 {
15081508 // Close handle is left from the desired mem.
15091509 leftTrueRightFalse = false;
15101510 }
1511- else if ( beg_intResult == memBlockSlice_t::INTERSECT_FLOATING_END )
1511+ else if ( beg_intResult == eir::INTERSECT_FLOATING_END )
15121512 {
15131513 // Close handle is right from the desired mem.
15141514 leftTrueRightFalse = true;
@@ -1548,16 +1548,16 @@
15481548 {
15491549 prettyCloseHandle = LIST_GETITEM( pageHandle, nextNode, managerNode );
15501550
1551- memBlockSlice_t::eIntersectionResult intResult =
1551+ eir::eIntersectionResult intResult =
15521552 prettyCloseHandle->requestedMemory.intersectWith( desiredMemSlice );
15531553
1554- assert( memBlockSlice_t::isFloatingIntersect( intResult ) == true );
1554+ assert( eir::isFloatingIntersect( intResult ) == true );
15551555
15561556 // We try to find the one that is our way.
15571557 if ( leftTrueRightFalse )
15581558 {
15591559 // Left.
1560- if ( intResult == memBlockSlice_t::INTERSECT_FLOATING_START )
1560+ if ( intResult == eir::INTERSECT_FLOATING_START )
15611561 {
15621562 // We append to nextCloseHandle.
15631563 reachedTheEnd = true;
@@ -1566,7 +1566,7 @@
15661566 else
15671567 {
15681568 // Right.
1569- if ( intResult == memBlockSlice_t::INTERSECT_FLOATING_END )
1569+ if ( intResult == eir::INTERSECT_FLOATING_END )
15701570 {
15711571 // We insert to nextCloseHandle.
15721572 reachedTheEnd = true;
--- common/sdk/OSUtils.memheap.h (revision 170)
+++ common/sdk/OSUtils.memheap.h (revision 171)
@@ -659,10 +659,10 @@
659659
660660 memBlockSlice_t requiredMemRegion( allocOff, reqSize );
661661
662- memBlockSlice_t::eIntersectionResult intResult = requiredMemRegion.intersectWith( smallFreeBlock->freeRegion );
662+ eir::eIntersectionResult intResult = requiredMemRegion.intersectWith( smallFreeBlock->freeRegion );
663663
664- if ( intResult == memBlockSlice_t::INTERSECT_INSIDE ||
665- intResult == memBlockSlice_t::INTERSECT_EQUAL )
664+ if ( intResult == eir::INTERSECT_INSIDE ||
665+ intResult == eir::INTERSECT_EQUAL )
666666 {
667667 // We found a valid allocation slot!
668668 // So return it.
--- common/sdk/SortedSliceSector.h (revision 170)
+++ common/sdk/SortedSliceSector.h (revision 171)
@@ -22,7 +22,7 @@
2222 #ifndef _EIR_SORTED_SLICE_SECTOR_HEADER_
2323 #define _EIR_SORTED_SLICE_SECTOR_HEADER_
2424
25-#include "MemoryRaw.h"
25+#include "MathSlice.h"
2626 #include "AVLTree.h"
2727 #include "eirutils.h"
2828 #include "MetaHelpers.h"
@@ -34,12 +34,12 @@
3434 template <typename numberType>
3535 struct SortedSliceSectorStdMetadata
3636 {
37- AINLINE SortedSliceSectorStdMetadata( sliceOfData <numberType> slice ) : slice( std::move( slice ) )
37+ AINLINE SortedSliceSectorStdMetadata( mathSlice <numberType> slice ) : slice( std::move( slice ) )
3838 {
3939 return;
4040 }
4141
42- AINLINE void Update( sliceOfData <numberType> newSlice )
42+ AINLINE void Update( mathSlice <numberType> newSlice )
4343 {
4444 this->slice = std::move( newSlice );
4545 }
@@ -49,18 +49,18 @@
4949 return;
5050 }
5151
52- AINLINE sliceOfData <numberType> GetNodeSlice( void ) const
52+ AINLINE mathSlice <numberType> GetNodeSlice( void ) const
5353 {
5454 return slice;
5555 }
5656
57- AINLINE operator const sliceOfData <numberType>& ( void ) const
57+ AINLINE operator const mathSlice <numberType>& ( void ) const
5858 {
5959 return slice;
6060 }
6161
6262 private:
63- sliceOfData <numberType> slice;
63+ mathSlice <numberType> slice;
6464 };
6565
6666 template <typename numberType, typename allocatorType, typename metaDataType = SortedSliceSectorStdMetadata <numberType>>
@@ -70,7 +70,7 @@
7070 // * sectorSlice_t GetNodeSlice( void ) const;
7171 // * template <typename... updateArgs> void Update( const sectorSlice_t& newSlice, updateArgs... args );
7272
73- typedef sliceOfData <numberType> sectorSlice_t;
73+ typedef mathSlice <numberType> sectorSlice_t;
7474
7575 private:
7676 struct sliceNode
@@ -347,13 +347,71 @@
347347 return sectorSlice_t::fromOffsets( rangeMin, rangeMax );
348348 }
349349
350+ // Runs through all slices that have a shared region with the input and passes
351+ // them to the callback. Also passes all slices inbetween that are not in the
352+ // list, if desired.
353+ template <typename callbackType>
354+ AINLINE void ScanSharedSlices( const sectorSlice_t& sliceShared, const callbackType& cb, bool includeNotPresent = false )
355+ {
356+ AVLNode *avlBeginNode = this->data.avlSliceTree.FindMinimumNodeByCriteria(
357+ [&]( AVLNode *leftNode )
358+ {
359+ return _CompareNodeWithSlice( leftNode, sliceShared, false );
360+ });
361+
362+ if ( avlBeginNode == nullptr )
363+ return;
364+
365+ numberType lastSliceContinuationPoint;
366+
367+ if ( includeNotPresent )
368+ {
369+ lastSliceContinuationPoint = sliceShared.GetSliceStartPoint();
370+ }
371+
372+ avlSliceTree_t::diff_node_iterator iter( avlBeginNode );
373+
374+ sliceNode *curNode = AVL_GETITEM( sliceNode, avlBeginNode, node );
375+
376+ sectorSlice_t curSlice = curNode->GetNodeSlice();
377+
378+ while ( true )
379+ {
380+ if ( includeNotPresent )
381+ {
382+ // If we have a region prior to our region, then we must report it.
383+
384+ }
385+
386+ iter.Increment();
387+
388+ if ( iter.IsEnd() )
389+ {
390+ break;
391+ }
392+
393+ // Fetch the next node pointer.
394+ curNode = AVL_GETITEM( sliceNode, iter.Resolve(), node );
395+
396+ curSlice = curNode->GetNodeSlice();
397+
398+ // Is that node still in the region?
399+ eCompResult cmpRes = _CompareSlices( curSlice, sliceShared, false );
400+
401+ if ( cmpRes != eCompResult::EQUAL )
402+ {
403+ break;
404+ }
405+ }
406+ }
407+
350408 private:
351409 static AINLINE eCompResult _CompareSlices( const sectorSlice_t& leftSlice, const sectorSlice_t& rightSlice, bool doCountInNeighbors )
352410 {
353411 // Here we can have an intersection, so treat any intersection as equality.
354- sectorSlice_t::eIntersectionResult intResult = leftSlice.intersectWith( rightSlice );
412+ eir::eIntersectionResult intResult = leftSlice.intersectWith( rightSlice );
355413
356- if ( intResult == sectorSlice_t::INTERSECT_FLOATING_START )
414+ if ( intResult == eir::INTERSECT_FLOATING_START )
357415 {
358416 if ( doCountInNeighbors )
359417 {
@@ -366,7 +424,7 @@
366424
367425 return eCompResult::LEFT_LESS;
368426 }
369- if ( intResult == sectorSlice_t::INTERSECT_FLOATING_END )
427+ if ( intResult == eir::INTERSECT_FLOATING_END )
370428 {
371429 if ( doCountInNeighbors )
372430 {
--- unittests/src/main.cpp (revision 170)
+++ unittests/src/main.cpp (revision 171)
@@ -9,10 +9,11 @@
99
1010 // We put this into a seperate file because there are IDEs which simply break character encodings
1111 // because they store things in incompatible internal formats.
12-extern void UNICODE_TEST( void );
12+extern void MATHSLICE_TESTS( void );
1313 extern void IMPLEMENTATION_TESTS( void );
1414 extern void MEM_TESTS( void );
1515 extern void HEAP_TESTS( void );
16+extern void UNICODE_TEST( void );
1617 extern void DTS_TESTS( void );
1718 extern void AVLTREE_TESTS( void );
1819 extern void VECTOR_TESTS( void );
@@ -32,10 +33,11 @@
3233 int main( int argc, char *argv[] )
3334 {
3435 // meow.
35- UNICODE_TEST();
36+ MATHSLICE_TESTS();
3637 IMPLEMENTATION_TESTS();
3738 MEM_TESTS();
3839 HEAP_TESTS();
40+ UNICODE_TEST();
3941 DTS_TESTS();
4042 AVLTREE_TESTS();
4143 VECTOR_TESTS();
--- unittests/src/mathslice.cpp (nonexistent)
+++ unittests/src/mathslice.cpp (revision 171)
@@ -0,0 +1,470 @@
1+#include <sdk/MathSlice.h>
2+
3+#include <assert.h>
4+
5+// I mainly do the bounds test not to check the trivial functionality but to ensure future functionality under
6+// refactoring if the template stuff is changed. Also to just compile all supported templating-paths.
7+
8+static void BOUNDS_TESTS( void )
9+{
10+ static_assert( sizeof(eir::lowerBound <int>) == sizeof(int), "eir::lowerBound with integral no good memory guarrantee" );
11+
12+ printf( "testing lowerBound construction..." );
13+ {
14+ eir::lowerBound <float> bound;
15+
16+ assert( bound.get_value() == 0.f );
17+ assert( bound.is_included() == true );
18+ }
19+ printf( "ok.\n" );
20+
21+ printf( "testing lowerBound value construction..." );
22+ {
23+ eir::lowerBound <float> bound( 5 );
24+
25+ assert( bound.get_value() == 5.f );
26+ assert( bound.is_included() == true );
27+ }
28+ printf( "ok.\n" );
29+
30+ printf( "testing lowerBound advanced construction..." );
31+ {
32+ // int
33+ {
34+ eir::lowerBound <int> excludedBound( 5, false );
35+
36+ assert( excludedBound.get_value() == 6 );
37+ assert( excludedBound.is_included() == true );
38+
39+ eir::lowerBound <int> includedBound( 5, true );
40+
41+ assert( includedBound.get_value() == 5 );
42+ assert( includedBound.is_included() == true );
43+ }
44+
45+ // float
46+ {
47+ eir::lowerBound <float> excludedBound( 5, false );
48+
49+ assert( excludedBound.get_value() == 5.f );
50+ assert( excludedBound.is_included() == false );
51+
52+ eir::lowerBound <float> includedBound( 5, true );
53+
54+ assert( includedBound.get_value() == 5.f );
55+ assert( includedBound.is_included() == true );
56+ }
57+ }
58+ printf( "ok.\n" );
59+
60+ printf( "testing lowerBound comparison..." );
61+ {
62+ // Integer.
63+ {
64+ eir::lowerBound <int> bound( 4 );
65+
66+ assert( bound.is_bounded( 4 ) == true );
67+ assert( bound.is_bounded( 3 ) == false );
68+ assert( bound.is_bounded( 5 ) == true );
69+
70+ assert( bound <= 4 );
71+ assert( bound > 3 );
72+ assert( bound <= 5 );
73+ }
74+
75+ // Float.
76+ {
77+ eir::lowerBound <float> includedBound( 4 );
78+
79+ assert( includedBound.is_bounded( 4 ) == true );
80+ assert( includedBound.is_bounded( 3 ) == false );
81+ assert( includedBound.is_bounded( 5 ) == true );
82+
83+ assert( includedBound <= 4 );
84+ assert( includedBound > 3 );
85+ assert( includedBound <= 5 );
86+
87+ eir::lowerBound <float> excludedBound( 4, false );
88+
89+ assert( excludedBound.is_bounded( 4 ) == false );
90+ assert( excludedBound.is_bounded( 4.5 ) == true );
91+ assert( excludedBound.is_bounded( 5 ) == true );
92+ assert( excludedBound.is_bounded( 3 ) == false );
93+ }
94+ }
95+ printf( "ok.\n" );
96+
97+ printf( "testing lowerBound highbound method..." );
98+ {
99+ eir::lowerBound <int> bound;
100+
101+ assert( bound.get_value() == 0 );
102+
103+ bound.highbound( 2 );
104+ assert( bound.get_value() == 2 );
105+
106+ bound.highbound( 1 );
107+ assert( bound.get_value() == 2 );
108+
109+ bound.highbound( 2, false );
110+ assert( bound.get_value() == 3 );
111+ }
112+ printf( "ok.\n" );
113+
114+ static_assert( sizeof(eir::upperBound <int>) == sizeof(int), "eir::upperBound with integral no good memory guarrantee" );
115+
116+ printf( "testing upperBound construction..." );
117+ {
118+ eir::upperBound <int> bound;
119+
120+ assert( bound.get_value() == 0 );
121+ assert( bound.is_included() == true );
122+ }
123+ printf( "ok.\n" );
124+
125+ printf( "testing upperBound value construction..." );
126+ {
127+ eir::upperBound <int> bound( 7 );
128+
129+ assert( bound.get_value() == 7 );
130+ assert( bound.is_included() == true );
131+ }
132+ printf( "ok.\n" );
133+
134+ printf( "testing upperBound advanced construction..." );
135+ {
136+ // int
137+ {
138+ eir::upperBound <int> includedBound( 5, true );
139+
140+ assert( includedBound.get_value() == 5 );
141+ assert( includedBound.is_included() == true );
142+
143+ eir::upperBound <int> excludedBound( 5, false );
144+
145+ assert( excludedBound.get_value() == 4 );
146+ assert( excludedBound.is_included() == true );
147+
148+ eir::upperBound <int> minus_one = eir::upperBound <int>::minus_one();
149+
150+ assert( minus_one.get_value() == -1 );
151+ assert( minus_one.is_included() == true );
152+ }
153+
154+ // float
155+ {
156+ eir::upperBound <float> includedBound( 5, true );
157+
158+ assert( includedBound.get_value() == 5 );
159+ assert( includedBound.is_included() == true );
160+
161+ eir::upperBound <float> excludedBound( 5, false );
162+
163+ assert( excludedBound.get_value() == 5 );
164+ assert( excludedBound.is_included() == false );
165+
166+ eir::upperBound <float> minus_one = eir::upperBound <float>::minus_one();
167+
168+ assert( minus_one.get_value() == -1 );
169+ assert( minus_one.is_included() == true );
170+ }
171+
172+ // unsigned int
173+ {
174+ eir::upperBound <unsigned int> bound( std::numeric_limits <unsigned int>::max() );
175+
176+ assert( bound.get_value() == std::numeric_limits <unsigned int>::max() );
177+ assert( bound.is_included() == true );
178+
179+ eir::upperBound <unsigned int> minus_one = eir::upperBound <unsigned int>::minus_one();
180+
181+ assert( minus_one.get_value() == std::numeric_limits <unsigned int>::max() );
182+ assert( minus_one.is_included() == true );
183+ }
184+ }
185+ printf( "ok.\n" );
186+
187+ printf( "testing upperBound comparison..." );
188+ {
189+ // int
190+ {
191+ eir::upperBound <int> bound( 9 );
192+
193+ assert( bound.is_bounded( 8 ) == true );
194+ assert( bound.is_bounded( 9 ) == true );
195+ assert( bound.is_bounded( 10 ) == false );
196+
197+ assert( 8 <= bound );
198+ assert( 9 <= bound );
199+ assert( 10 > bound );
200+ }
201+
202+ // float
203+ {
204+ eir::upperBound <float> includedBound( 8 );
205+
206+ assert( includedBound.is_bounded( 8 ) == true );
207+ assert( includedBound.is_bounded( 9 ) == false );
208+ assert( includedBound.is_bounded( 7 ) == true );
209+
210+ eir::upperBound <float> excludedBound( 8, false );
211+
212+ assert( excludedBound.is_bounded( 8 ) == false );
213+ assert( excludedBound.is_bounded( 7.5 ) == true );
214+ assert( excludedBound.is_bounded( 8.5 ) == false );
215+ }
216+
217+ // unsigned int
218+ {
219+ eir::upperBound <unsigned int> bound( 5 );
220+
221+ assert( bound.is_bounded( 5 ) == true );
222+ assert( bound.is_bounded( std::numeric_limits <unsigned int>::max() ) == true ); // special case: max is actually -1.
223+ assert( bound.is_bounded( std::numeric_limits <unsigned int>::max() - 1 ) == false );
224+ }
225+ }
226+ printf( "ok.\n" );
227+
228+ printf( "testing upperBound lowbound method..." );
229+ {
230+ // regular testing.
231+ {
232+ eir::upperBound <int> bound;
233+
234+ assert( bound.get_value() == 0 );
235+
236+ bound.lowbound( -2 );
237+ assert( bound.get_value() == -2 );
238+
239+ bound.lowbound( -1 );
240+ assert( bound.get_value() == -2 );
241+
242+ bound.lowbound( -2 );
243+ assert( bound.get_value() == -2 );
244+
245+ bound.lowbound( -2, false );
246+ assert( bound.get_value() == -3 );
247+ }
248+
249+ // unsigned int.
250+ {
251+ eir::upperBound <unsigned int> bound;
252+
253+ assert( bound.get_value() == 0 );
254+
255+ bound.lowbound( 0, false );
256+ assert( bound.get_value() == std::numeric_limits <unsigned int>::max() );
257+
258+ bound.lowbound( 0, false );
259+ assert( bound.get_value() == std::numeric_limits <unsigned int>::max() );
260+
261+ bound.lowbound( 5, true );
262+ assert( bound.get_value() == std::numeric_limits <unsigned int>::max() );
263+
264+ eir::upperBound <unsigned int> trivialBound( 6 );
265+
266+ assert( trivialBound.get_value() == 6 );
267+
268+ trivialBound.lowbound( 5 );
269+ assert( trivialBound.get_value() == 5 );
270+
271+ trivialBound.lowbound( 6 );
272+ assert( trivialBound.get_value() == 5 );
273+
274+ trivialBound.lowbound( 5 );
275+ assert( trivialBound.get_value() == 5 );
276+
277+ trivialBound.lowbound( 5, false );
278+ assert( trivialBound.get_value() == 4 );
279+ }
280+ }
281+ printf( "ok.\n" );
282+}
283+
284+void MATHSLICE_TESTS( void )
285+{
286+ BOUNDS_TESTS();
287+
288+ static_assert( sizeof(eir::mathSlice <size_t>) == sizeof(size_t) * 2, "non-optimized unsigned eir::mathSlice representation" );
289+
290+ printf( "testing slice construction..." );
291+ {
292+ // unsigned
293+ {
294+ eir::mathSlice <size_t> slice;
295+
296+ assert( slice.IsEmpty() == true );
297+ }
298+
299+ // int
300+ {
301+ eir::mathSlice <int> slice;
302+
303+ assert( slice.IsEmpty() == true );
304+ }
305+
306+ // float
307+ {
308+ eir::mathSlice <float> slice;
309+
310+ assert( slice.IsEmpty() == true );
311+ }
312+ }
313+ printf( "ok.\n" );
314+
315+ printf( "testing slice intersect equal..." );
316+ {
317+ // unsigned
318+ {
319+ eir::mathSlice <unsigned int> one( 4, 2 );
320+ eir::mathSlice <unsigned int> two( 4, 2 );
321+
322+ assert( one.intersectWith( two ) == eir::INTERSECT_EQUAL );
323+ }
324+
325+ // int
326+ {
327+ eir::mathSlice <int> one( 7, 3 );
328+ eir::mathSlice <int> two( 7, 3 );
329+
330+ assert( one.intersectWith( two ) == eir::INTERSECT_EQUAL );
331+ }
332+
333+ // float
334+ {
335+ eir::mathSlice <float> one( 5, 2.2f );
336+ eir::mathSlice <float> two( 5, 2.2f );
337+
338+ assert( one.intersectWith( two ) == eir::INTERSECT_EQUAL );
339+
340+ // Not actually equal.
341+ auto inclusive_borders = eir::mathSlice <float>::fromOffsets( 3, 6, true, true );
342+ auto non_inclusive_borders = eir::mathSlice <float>::fromOffsets( 3, 6, false, false );
343+
344+ assert( inclusive_borders.intersectWith( non_inclusive_borders ) == eir::INTERSECT_ENCLOSING );
345+ }
346+ }
347+ printf( "ok.\n" );
348+
349+ printf( "testing slice intersect inside..." );
350+ {
351+ // int
352+ {
353+ eir::mathSlice <int> one( 4, 3 );
354+ eir::mathSlice <int> two( 3, 5 );
355+
356+ assert( one.intersectWith( two ) == eir::INTERSECT_INSIDE );
357+ }
358+
359+ // float
360+ {
361+ eir::mathSlice <float> one( 3, 1.5f );
362+ eir::mathSlice <float> two( 2, 9 );
363+
364+ assert( one.intersectWith( two ) == eir::INTERSECT_INSIDE );
365+ }
366+ }
367+ printf( "ok.\n" );
368+
369+ printf( "testing slice intersect border start..." );
370+ {
371+ // int
372+ {
373+ eir::mathSlice <int> one( 2, 4 );
374+ eir::mathSlice <int> two( 1, 2 );
375+
376+ assert( one.intersectWith( two ) == eir::INTERSECT_BORDER_START );
377+ }
378+
379+ // float
380+ {
381+ eir::mathSlice <float> one( 7, 2.2f );
382+ eir::mathSlice <float> two( 5, 3 );
383+
384+ assert( one.intersectWith( two ) == eir::INTERSECT_BORDER_START );
385+ }
386+ }
387+ printf( "ok.\n" );
388+
389+ printf( "testing slice intersect border end..." );
390+ {
391+ // int
392+ {
393+ eir::mathSlice <int> one( 2, 4 );
394+ eir::mathSlice <int> two( 3, 9 );
395+
396+ assert( one.intersectWith( two ) == eir::INTERSECT_BORDER_END );
397+ }
398+
399+ // float
400+ {
401+ eir::mathSlice <float> one( 3.3f, 2 );
402+ eir::mathSlice <float> two( 4, 7 );
403+
404+ assert( one.intersectWith( two ) == eir::INTERSECT_BORDER_END );
405+ }
406+ }
407+ printf( "ok.\n" );
408+
409+ printf( "testing slice intersect enclosing..." );
410+ {
411+ // int
412+ {
413+ eir::mathSlice <int> one( 1, 8 );
414+ eir::mathSlice <int> two( 3, 4 );
415+
416+ assert( one.intersectWith( two ) == eir::INTERSECT_ENCLOSING );
417+ }
418+
419+ // float
420+ {
421+ eir::mathSlice <float> one( 3.4f, 0.8f );
422+ eir::mathSlice <float> two( 3.6f, 0.1f );
423+
424+ assert( one.intersectWith( two ) == eir::INTERSECT_ENCLOSING );
425+ }
426+ }
427+ printf( "ok.\n" );
428+
429+ printf( "testing slice intersect floating start..." );
430+ {
431+ // int
432+ {
433+ eir::mathSlice <int> one( 2, 2 );
434+ eir::mathSlice <int> two( 5, 2 );
435+
436+ assert( one.intersectWith( two ) == eir::INTERSECT_FLOATING_START );
437+ }
438+
439+ // float
440+ {
441+ eir::mathSlice <float> one( 1, 3.3f );
442+ eir::mathSlice <float> two( 6, 3.3f );
443+
444+ assert( one.intersectWith( two ) == eir::INTERSECT_FLOATING_START );
445+ }
446+ }
447+ printf( "ok.\n" );
448+
449+ printf( "testing slice intersect floating end..." );
450+ {
451+ // int
452+ {
453+ eir::mathSlice <int> one( 9, 2 );
454+ eir::mathSlice <int> two( 4, 4 );
455+
456+ assert( one.intersectWith( two ) == eir::INTERSECT_FLOATING_END );
457+ }
458+
459+ // float
460+ {
461+ eir::mathSlice <float> one( 22, 9 );
462+ eir::mathSlice <float> two( 1, 5.5f );
463+
464+ assert( one.intersectWith( two ) == eir::INTERSECT_FLOATING_END );
465+ }
466+ }
467+ printf( "ok.\n" );
468+
469+ // TODO: add more non-trivial test cases for slice intersection.
470+}
\ No newline at end of file
--- unittests/src/sortedslicesector.cpp (revision 170)
+++ unittests/src/sortedslicesector.cpp (revision 171)
@@ -13,22 +13,22 @@
1313
1414 printf( "testing number neighbors..." );
1515 {
16- assert( IsNumberInNeighborhood( 1, 1 ) == true );
17- assert( IsNumberInNeighborhood( 1, 2 ) == true );
18- assert( IsNumberInNeighborhood( 1, 0 ) == true );
19- assert( IsNumberInNeighborhood( 1u, 1 ) == true );
20- assert( IsNumberInNeighborhood( 1, 1u ) == true );
21- assert( IsNumberInNeighborhood( 1, 0u ) == true );
22- assert( IsNumberInNeighborhood( 1u, 0 ) == true );
16+ assert( eir::IsNumberInNeighborhood( 1, 1 ) == true );
17+ assert( eir::IsNumberInNeighborhood( 1, 2 ) == true );
18+ assert( eir::IsNumberInNeighborhood( 1, 0 ) == true );
19+ assert( eir::IsNumberInNeighborhood( 1u, 1 ) == true );
20+ assert( eir::IsNumberInNeighborhood( 1, 1u ) == true );
21+ assert( eir::IsNumberInNeighborhood( 1, 0u ) == true );
22+ assert( eir::IsNumberInNeighborhood( 1u, 0 ) == true );
2323
24- assert( IsNumberInNeighborhood( 1, 3 ) == false );
25- assert( IsNumberInNeighborhood( 1u, 3u ) == false );
26- assert( IsNumberInNeighborhood( 1, 3u ) == false );
24+ assert( eir::IsNumberInNeighborhood( 1, 3 ) == false );
25+ assert( eir::IsNumberInNeighborhood( 1u, 3u ) == false );
26+ assert( eir::IsNumberInNeighborhood( 1, 3u ) == false );
2727
28- assert( IsNumberInNeighborhood( 3.f, 3u ) == true );
29- assert( IsNumberInNeighborhood( 3.f, 3 ) == true );
30- assert( IsNumberInNeighborhood( 3.f, 2u ) == false );
31- assert( IsNumberInNeighborhood( 3.f, 4u ) == false );
28+ assert( eir::IsNumberInNeighborhood( 3.f, 3u ) == true );
29+ assert( eir::IsNumberInNeighborhood( 3.f, 3 ) == true );
30+ assert( eir::IsNumberInNeighborhood( 3.f, 2u ) == false );
31+ assert( eir::IsNumberInNeighborhood( 3.f, 4u ) == false );
3232 }
3333 printf( "ok.\n" );
3434
Show on old repository browser