Skip to content

Point V : gaol::lexicographic_less, un ordre total pour std::set, std::sort et std::map - #96

Merged
Jordan08 merged 4 commits into
configure-cleanfrom
todo-v-lexicographic-less
Oct 6, 2026
Merged

Jordan08 merged 4 commits into
configure-cleanfrom
todo-v-lexicographic-less

Conversation

@Jordan08

@Jordan08 Jordan08 commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Point V de TODO.md : un ordre total pour les conteneurs (ancien 22).

gaol::lexicographic_less

Problème : <, <=, > et >= entre intervalles sont les relations
« certainement » d'IEEE 1788-2015 (operator< est certainly_le(),
strictPrecedes, gaol/gaol_interval.h), vraies dès qu'un des deux
intervalles est vide. Un std::set<gaol::interval> sans comparateur perd
donc les intervalles qui se chevauchent, et tout intervalle une fois
l'ensemble vide inséré ; std::sort d'un vecteur contenant un intervalle
vide lit au-delà de sa fin ; std::max, std::min et std::clamp
n'ordonnent pas non plus.

Correction : gaol_core::lexicographic_less, une structure que la
bibliothèque standard prend comme comparateur
(std::set<interval, gaol::lexicographic_less>), nommée dans gaol par
une using-déclaration à sa place alphabétique. L'ensemble vide vient
d'abord, puis les intervalles par borne inférieure, puis par borne
supérieure, les infinis compris ; -0.0 et +0.0 sont égales comme
bornes. L'ordre est strict : less(I, I) est faux, et deux intervalles
de mêmes bornes ne sont pas l'un moins que l'autre.

La spécialisation de std::less pour gaol::interval reste reportée
(issue #70), comme la mise en garde dans doc/using.md et le manuel
contre std::sort, std::set, std::max, std::min et std::clamp
sans comparateur, qui va avec le point I.

Tests

relations gagne test_lexicographic_less (332 vérifications) :

  • l'ordre attendu de dix intervalles pris deux à deux (avec l'ensemble
    vide et les bornes infinies), et qu'un ordre strict ne donne jamais
    less(a, b) et less(b, a) ensemble ;
  • less(I, I) faux, y compris pour l'ensemble vide ;
  • -0.0 et +0.0 égales comme bornes ;
  • un std::set qui garde quatre intervalles dont trois qui se
    chevauchent et l'ensemble vide ;
  • un std::sort d'un vecteur contenant l'ensemble vide.

misc vérifie en outre que gaol::lexicographic_less est bien la
classe de gaol_core (GAOL_NAMES_CLASS), comme chaque nom de gaol.

Vérifié : avec les sources de configure-clean, un programme qui
refait les deux derniers avec < (certainly_le) comme comparateur
donne set size: 2 au lieu de 4, et le premier élément du vecteur
trié n'est pas l'ensemble vide : les deux assertions échouent sans
la correction. Le std::sort avec < d'un vecteur de 102 intervalles
dont un vide lève un heap-buffer-overflow sous
-fsanitize=address (GCC 14, libstdc++), lu de 16 octets au-delà de
la fin : l'affirmation de doc/tests.md est mesurée.

Pour doc/differences.md et ChangeLog (pull request de synthèse)

  • gaol::lexicographic_less : un ordre total strict sur les intervalles
    pour les conteneurs de la bibliothèque standard, que < n'est pas,
    étant strictPrecedes d'IEEE 1788-2015 (GAOL v5).

Relecture

Relecture indépendante du diff complet, puis une seconde relecture
après les premiers correctifs. La première a trouvé et corrigé : le
doublon de déclaration du foncteur dans le test ; le commentaire
Doxygen qui disait « lexicographic_less() (I, I) » pour un appel de
fonction alors que c'est un foncteur (dit « less(I, I) » maintenant) ;
le tableau de test mal ordonné (universe() avant (-oo, 1)), dont
12 vérifications échouaient ; l'ordre alphabétique des
using-déclarations. La seconde a trouvé et corrigé : misc ne
vérifiait pas le nouveau nom de gaol (GAOL_NAMES_CLASS
ajouté, commit 02bfa09) ; le corps de la pull request annonçait
652 vérifications pour 332. Elle a vérifié en outre : la totalité,
l'antisymétrie et la transitivité de l'ordre sur 900 paires et
27 000 triples d'intervalles construits de bornes parmi
{-oo, -2, -0.0, +0.0, 1, 2, +oo} et l'ensemble vide (programme
indépendant, zéro contre-exemple) ; qu'un intervalle à borne NaN,
vide, y est ordonné comme l'ensemble vide sans lever FE_INVALID
(sous fetestexcept) ; que quatre ensembles vides construits
différemment (interval(nan, 1), interval(-1, nan),
interval(nan, nan), interval::emptyset()) sont égaux dans
l'ordre, un std::set n'en gardant qu'un ; le heap-buffer-overflow
de std::sort avec < cité plus haut ; que le point 8 de la revue
d'examples/examples.md (l. 942) est bien ce que ce changement
implémente ; qu'aucun fichier généré ni registre n'est touché.

Vérifié en local

  • CMake SSE2 (WITH_TESTS=ON) : build sans avertissement, 41/41 tests,
    dont relations (765 vérifications, 0 échec) et misc ;
  • CMake FPU (GAOL_SIMD=OFF) : 41/41 tests ;
  • CMake Debug avec les sanitizers (-fsanitize=address,undefined -fno-omit-frame-pointer dans les drapeaux C, C++ et de l'édition de
    liens) : 41/41 tests, aucun rapport d'AddressSanitizer ni de
    UndefinedBehaviorSanitizer, relations (765 vérifications) et misc
    compris ;
  • CMake -Wall -Wextra -Werror GCC : sans avertissement, 41/41 tests ;
  • autotools : make -j4, make -j4 check sans échec (29 PASS, 0 FAIL,
    0 ERROR), puis make distclean rend l'arbre tel que git l'a ;
  • meson (meson 1.12.1, ninja 1.10.2 ici, au-dessus du minimum 0.53.2) :
    build, 31/31 tests, 0 échec ;
  • GAOL installé : sh .github/scripts/tests.sh <prefix> static puis
    shared (292 728 + 390 vérifications, 0 échec), et
    sh .github/scripts/headers.sh <prefix> : chaque en-tête compile
    seul ;
  • relations et numbers sous fr_FR.UTF-8 : passés ;
  • lignes des fichiers modifiés : 80 colonnes au plus.

Non vérifiable ici : Clang 18, AppleClang, Visual C++ et clang-cl,
ARM, gros-boutiste, Alpine. La sandbox n'a que GCC : le foncteur
n'utilise que gaol_detail::quiet_less(), les mêmes comparaisons
silencieuses que les relations voisines, et rien de spécifique à un
compilateur.

Dépendances

Aucune.

Questions ouvertes

La spécialisation de std::less reste reportée (issue #70) ; la mise
en garde dans doc/using.md et le manuel se fera avec le point I,
comme le prévoit TODO.md.

@Jordan08
Jordan08 merged commit f2e9540 into configure-clean Oct 6, 2026
128 checks passed
Jordan08 added a commit that referenced this pull request Oct 6, 2026
@Jordan08
Jordan08 deleted the todo-v-lexicographic-less branch October 6, 2026 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant