Skip to content

Commit d6e865a

Browse files
committed
Fixed dot string comparisons, and introduced natural ordering.
There is some work to be done to extend strnatcmp to support view comparisons and not just null terminated strings. For now, a suboptimal implementation of the dot comparison based on natural ordering has been implemented, requiring memory allocations.
1 parent 576e1ed commit d6e865a

File tree

5 files changed

+45
-14
lines changed

5 files changed

+45
-14
lines changed

RELEASE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## v0.4.3
22

3+
### New features
4+
5+
- Natural ordering for strings is now supported
6+
37
### Breaking
48

59
- `s:enable` has been reworked as an overload of `s:when`.
10+
- Default string comparisons are now following natural ordering.

include/utils.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ inline bool cexpr_streqv(const char* s, const char* c){return strcmp(s, c)==0;}
5050
*/
5151
int cmp_dot_str(const char* a, const char* b);
5252

53+
/**
54+
* @brief Compare two strings (natural comparison) assuming the dot notation for ordering nested fields
55+
*
56+
* @param a
57+
* @param b
58+
* @return int
59+
*/
60+
int cmp_dot_natstr(const char* a, const char* b);
61+
5362
//TODO: Add natural ordering
5463

5564
namespace hash{

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ vs_templ_lib = library(
3333
'src/logging.cpp',
3434
'src/stack-lang.cpp',
3535
],
36-
dependencies: [pugixml_dep, frozen_dep, ff_dep],
36+
dependencies: [pugixml_dep, frozen_dep, ff_dep, natsort_dep],
3737
include_directories: ['include'],
3838
install: not meson.is_subproject(),
3939
)

src/utils.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <utils.hpp>
2+
#include <strnatcmp.h>
23

34
namespace vs{
45
namespace templ{
@@ -21,13 +22,32 @@ int cmp_dot_str(const char* a, const char* b){
2122
if(va.size()<vb.size())return -1;
2223
else if(va.size()>vb.size())return 1;
2324

24-
for(size_t i =0;i<va.size();i++){
25+
for(size_t i=0;i<va.size();i++){
2526
if(va.at(i)<vb.at(i))return -1;
2627
else if(va.at(i)>vb.at(i))return 1;
2728
}
28-
return -1;
29+
return 0;
2930
}
3031

32+
int cmp_dot_natstr(const char* a, const char* b){
33+
auto va = split_string(a, '.');
34+
auto vb = split_string(b, '.');
35+
36+
if(va.size()<vb.size())return -1;
37+
else if(va.size()>vb.size())return 1;
38+
39+
for(size_t i=0;i<va.size();i++){
40+
//TODO: Implement the view version of strnatcmp, otherwise I am forced to perform these bad allocations
41+
std::string a = std::string(va.at(i));
42+
std::string b = std::string(vb.at(i));
43+
auto ret = strnatcmp(a.c_str(),b.c_str());
44+
if(ret<0)return -1;
45+
else if(ret>0)return 1;
46+
}
47+
return 0;
48+
}
49+
50+
3151
namespace hash{
3252

3353
#if defined(_MSC_VER)

src/vs-templ.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <string_view>
44
#include <variant>
55
#include <format>
6+
#include <strnatcmp.h>
67

78
#if (defined(__GNUC__) && __GNUC__ >= 13) || (defined(__clang__) && __clang_major__ >= 20) || (defined(_MSC_VER) && _MSC_VER >= 1910)
89
#include <charconv>
@@ -54,7 +55,7 @@ preprocessor::compare_result preprocessor::compare_symbols(const symbol& a, cons
5455
if(method.type==order_t::type_t::DEFAULT){
5556
if(std::holds_alternative<int>(a))method.type=order_t::type_t::INTEGER;
5657
else if(std::holds_alternative<float>(a))method.type=order_t::type_t::FLOAT;
57-
else if(std::holds_alternative<std::string>(a))method.type=order_t::type_t::STRING;//TODO: move to `order_t::type_t::NATURAL_STRING`
58+
else if(std::holds_alternative<std::string>(a))method.type=order_t::type_t::NATURAL_STRING;
5859
else if(std::holds_alternative<const pugi::xml_node>(a))method.type=order_t::type_t::NODE;
5960
}
6061

@@ -79,12 +80,11 @@ preprocessor::compare_result preprocessor::compare_symbols(const symbol& a, cons
7980
else if(std::holds_alternative<const pugi::xml_node>(a) && std::holds_alternative<const pugi::xml_node>(b) && method.type==order_t::type_t::NODE){
8081

8182
}
82-
else if(std::holds_alternative<std::string>(a) && std::holds_alternative<std::string>(b) && method.type==order_t::type_t::STRING){
83+
else if(std::holds_alternative<std::string>(a) && std::holds_alternative<std::string>(b) && (method.type==order_t::type_t::STRING || method.type==order_t::type_t::NATURAL_STRING ) ){
8384
const auto& _a = std::get<std::string>(a), _b = std::get<std::string>(b);
8485
if(method.modifiers.dot){
85-
auto i = cmp_dot_str(_a.c_str(), _b.c_str());
86-
if(method.method==order_t::method_t::ASC) return (i<0)?compare_result::LESS: ( (i>0)? compare_result::BIGGER : compare_result::EQUAL);
87-
else if(method.method==order_t::method_t::DESC) return (i<0)?compare_result::BIGGER: ( (i>0)? compare_result::LESS : compare_result::EQUAL);
86+
if(method.method==order_t::method_t::ASC){auto i = (method.type==order_t::type_t::NATURAL_STRING)?cmp_dot_natstr(_a.c_str(), _b.c_str()):cmp_dot_str(_a.c_str(), _b.c_str());return (i<0)?compare_result::LESS: ( (i>0)? compare_result::BIGGER : compare_result::EQUAL);}
87+
else if(method.method==order_t::method_t::DESC){auto i = -((method.type==order_t::type_t::NATURAL_STRING)?cmp_dot_natstr(_a.c_str(), _b.c_str()):cmp_dot_str(_a.c_str(), _b.c_str())); return (i<0)?compare_result::LESS: ( (i>0)? compare_result::BIGGER : compare_result::EQUAL);}
8888
else if(method.method==order_t::method_t::RANDOM){
8989
auto va = split_string(std::get<std::string>(a).c_str(), '.');
9090
auto vb = split_string(std::get<std::string>(b).c_str(), '.');
@@ -106,8 +106,8 @@ preprocessor::compare_result preprocessor::compare_symbols(const symbol& a, cons
106106
}
107107
}
108108
else{
109-
if(method.method==order_t::method_t::ASC) return (_a<_b)?compare_result::LESS: ( (_a>_b)? compare_result::BIGGER : compare_result::EQUAL);
110-
else if(method.method==order_t::method_t::DESC) return (_a<_b)?compare_result::BIGGER: ( (_a>_b)? compare_result::LESS : compare_result::EQUAL);
109+
if(method.method==order_t::method_t::ASC){auto cmp = (method.type==order_t::type_t::NATURAL_STRING)?strnatcmp(_a.c_str(),_b.c_str()):strcmp(_a.c_str(),_b.c_str()); return (cmp<0)?compare_result::LESS: ( (cmp>0)? compare_result::BIGGER : compare_result::EQUAL);}
110+
else if(method.method==order_t::method_t::DESC){auto cmp = -((method.type==order_t::type_t::NATURAL_STRING)?strnatcmp(_a.c_str(),_b.c_str()):strcmp(_a.c_str(),_b.c_str())); return (cmp<0)?compare_result::LESS: ( (cmp>0)? compare_result::BIGGER : compare_result::EQUAL);}
111111
else if(method.method==order_t::method_t::RANDOM){
112112
auto hash_a = preprocessor::hash(a);
113113
auto hash_b = preprocessor::hash(b);
@@ -116,10 +116,7 @@ preprocessor::compare_result preprocessor::compare_symbols(const symbol& a, cons
116116
}
117117
}
118118
else if(std::holds_alternative<std::string>(a) && std::holds_alternative<std::string>(b) && method.type==order_t::type_t::LEXI_STRING){
119-
120-
}
121-
else if(std::holds_alternative<std::string>(a) && std::holds_alternative<std::string>(b) && method.type==order_t::type_t::NATURAL_STRING){
122-
//https://github.com/sourcefrog/natsort
119+
//TODO: not implemented
123120
}
124121
//Cannot have pugi::xml_attribute since it has been resolved by the time it gets here.
125122

0 commit comments

Comments
 (0)