Skip to content

Commit c6cb449

Browse files
authored
Merge pull request #955 from jf2048/gstringptr-perf
Use strcmp for GStringPtr comparisons
2 parents 0d38c9a + fe8cab7 commit c6cb449

File tree

1 file changed

+91
-25
lines changed

1 file changed

+91
-25
lines changed

glib/src/gstring.rs

Lines changed: 91 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -144,16 +144,29 @@ impl GStr {
144144
/// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be
145145
/// nul-terminated. All constraints from [`std::ffi::CStr::from_ptr`] also apply here.
146146
///
147-
/// If the string is valid UTF-8 then it is directly returned otherwise a copy is created with
148-
/// every invalid character replaced by the Unicode replacement character (U+FFFD).
147+
/// If the string is valid UTF-8 then it is directly returned, otherwise `None` is returned.
149148
#[inline]
150-
pub unsafe fn from_ptr_lossy<'a>(ptr: *const c_char) -> Cow<'a, Self> {
149+
pub unsafe fn from_ptr_checked<'a>(ptr: *const c_char) -> Option<&'a Self> {
151150
let mut end_ptr = ptr::null();
152151
if ffi::g_utf8_validate(ptr as *const _, -1, &mut end_ptr) != ffi::GFALSE {
153-
Cow::Borrowed(Self::from_utf8_with_nul_unchecked(slice::from_raw_parts(
152+
Some(Self::from_utf8_with_nul_unchecked(slice::from_raw_parts(
154153
ptr as *const u8,
155154
end_ptr.offset_from(ptr) as usize + 1,
156155
)))
156+
} else {
157+
None
158+
}
159+
}
160+
// rustdoc-stripper-ignore-next
161+
/// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be
162+
/// nul-terminated. All constraints from [`std::ffi::CStr::from_ptr`] also apply here.
163+
///
164+
/// If the string is valid UTF-8 then it is directly returned otherwise a copy is created with
165+
/// every invalid character replaced by the Unicode replacement character (U+FFFD).
166+
#[inline]
167+
pub unsafe fn from_ptr_lossy<'a>(ptr: *const c_char) -> Cow<'a, Self> {
168+
if let Some(gs) = Self::from_ptr_checked(ptr) {
169+
Cow::Borrowed(gs)
157170
} else {
158171
Cow::Owned(GString::from_glib_full(ffi::g_utf8_make_valid(
159172
ptr as *const _,
@@ -684,6 +697,24 @@ impl GStringPtr {
684697
pub fn to_str(&self) -> &str {
685698
self.to_gstr().as_str()
686699
}
700+
701+
// rustdoc-stripper-ignore-next
702+
/// Returns the string's C pointer.
703+
#[inline]
704+
pub const fn as_ptr(&self) -> *const c_char {
705+
self.0.as_ptr()
706+
}
707+
708+
// rustdoc-stripper-ignore-next
709+
/// Wrapper around `libc::strcmp` returning `Ordering`.
710+
///
711+
/// # Safety
712+
///
713+
/// `a` and `b` must be non-null pointers to nul-terminated C strings.
714+
#[inline]
715+
unsafe fn strcmp(a: *const c_char, b: *const c_char) -> Ordering {
716+
from_glib(libc::strcmp(a, b))
717+
}
687718
}
688719

689720
impl Clone for GStringPtr {
@@ -693,6 +724,13 @@ impl Clone for GStringPtr {
693724
}
694725
}
695726

727+
impl IntoGlibPtr<*mut c_char> for GStringPtr {
728+
#[inline]
729+
unsafe fn into_glib_ptr(self) -> *mut c_char {
730+
self.0.as_ptr()
731+
}
732+
}
733+
696734
impl Drop for GStringPtr {
697735
#[inline]
698736
fn drop(&mut self) {
@@ -704,7 +742,7 @@ impl Drop for GStringPtr {
704742

705743
impl fmt::Debug for GStringPtr {
706744
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707-
f.write_str(self.to_str())
745+
<&GStr as fmt::Debug>::fmt(&self.to_gstr(), f)
708746
}
709747
}
710748

@@ -720,105 +758,105 @@ impl Eq for GStringPtr {}
720758
impl PartialEq for GStringPtr {
721759
#[inline]
722760
fn eq(&self, other: &GStringPtr) -> bool {
723-
self.to_gstr() == other.to_gstr()
761+
self.partial_cmp(other) == Some(Ordering::Equal)
724762
}
725763
}
726764

727765
impl PartialEq<GStringPtr> for String {
728766
#[inline]
729767
fn eq(&self, other: &GStringPtr) -> bool {
730-
self.as_str() == other.to_str()
768+
self.partial_cmp(other) == Some(Ordering::Equal)
731769
}
732770
}
733771

734772
impl PartialEq<GStringPtr> for GString {
735773
#[inline]
736774
fn eq(&self, other: &GStringPtr) -> bool {
737-
self.as_str() == other.to_str()
775+
self.partial_cmp(other) == Some(Ordering::Equal)
738776
}
739777
}
740778

741779
impl PartialEq<str> for GStringPtr {
742780
#[inline]
743781
fn eq(&self, other: &str) -> bool {
744-
self.to_str() == other
782+
self.partial_cmp(other) == Some(Ordering::Equal)
745783
}
746784
}
747785

748786
impl PartialEq<&str> for GStringPtr {
749787
#[inline]
750788
fn eq(&self, other: &&str) -> bool {
751-
self.to_str() == *other
789+
self.partial_cmp(other) == Some(Ordering::Equal)
752790
}
753791
}
754792

755793
impl PartialEq<GStr> for GStringPtr {
756794
#[inline]
757795
fn eq(&self, other: &GStr) -> bool {
758-
self.to_gstr() == other
796+
self.partial_cmp(other) == Some(Ordering::Equal)
759797
}
760798
}
761799

762800
impl PartialEq<&GStr> for GStringPtr {
763801
#[inline]
764802
fn eq(&self, other: &&GStr) -> bool {
765-
self.to_gstr() == *other
803+
self.partial_cmp(other) == Some(Ordering::Equal)
766804
}
767805
}
768806

769807
impl PartialEq<GStringPtr> for &str {
770808
#[inline]
771809
fn eq(&self, other: &GStringPtr) -> bool {
772-
*self == other.to_str()
810+
self.partial_cmp(other) == Some(Ordering::Equal)
773811
}
774812
}
775813

776814
impl PartialEq<GStringPtr> for &GStr {
777815
#[inline]
778816
fn eq(&self, other: &GStringPtr) -> bool {
779-
self.as_str() == other.to_str()
817+
self.partial_cmp(other) == Some(Ordering::Equal)
780818
}
781819
}
782820

783821
impl PartialEq<String> for GStringPtr {
784822
#[inline]
785823
fn eq(&self, other: &String) -> bool {
786-
self.to_str() == other.as_str()
824+
self.partial_cmp(other) == Some(Ordering::Equal)
787825
}
788826
}
789827

790828
impl PartialEq<GString> for GStringPtr {
791829
#[inline]
792830
fn eq(&self, other: &GString) -> bool {
793-
self.to_str() == other.as_str()
831+
self.partial_cmp(other) == Some(Ordering::Equal)
794832
}
795833
}
796834

797835
impl PartialEq<GStringPtr> for str {
798836
#[inline]
799837
fn eq(&self, other: &GStringPtr) -> bool {
800-
self == other.to_str()
838+
self.partial_cmp(other) == Some(Ordering::Equal)
801839
}
802840
}
803841

804842
impl PartialEq<GStringPtr> for GStr {
805843
#[inline]
806844
fn eq(&self, other: &GStringPtr) -> bool {
807-
self == other.to_gstr()
845+
self.partial_cmp(other) == Some(Ordering::Equal)
808846
}
809847
}
810848

811849
impl PartialOrd<GStringPtr> for GStringPtr {
812850
#[inline]
813851
fn partial_cmp(&self, other: &GStringPtr) -> Option<std::cmp::Ordering> {
814-
Some(self.to_gstr().cmp(other.to_gstr()))
852+
Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) })
815853
}
816854
}
817855

818856
impl Ord for GStringPtr {
819857
#[inline]
820858
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
821-
self.to_gstr().cmp(other.to_gstr())
859+
unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) }
822860
}
823861
}
824862

@@ -832,21 +870,21 @@ impl PartialOrd<GStringPtr> for String {
832870
impl PartialOrd<GStringPtr> for GString {
833871
#[inline]
834872
fn partial_cmp(&self, other: &GStringPtr) -> Option<std::cmp::Ordering> {
835-
Some(self.as_str().cmp(other.to_str()))
873+
Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) })
836874
}
837875
}
838876

839877
impl PartialOrd<String> for GStringPtr {
840878
#[inline]
841879
fn partial_cmp(&self, other: &String) -> Option<std::cmp::Ordering> {
842-
Some(self.to_str().cmp(other.as_str()))
880+
Some(self.to_str().cmp(other))
843881
}
844882
}
845883

846884
impl PartialOrd<GString> for GStringPtr {
847885
#[inline]
848886
fn partial_cmp(&self, other: &GString) -> Option<std::cmp::Ordering> {
849-
Some(self.to_str().cmp(other.as_str()))
887+
Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) })
850888
}
851889
}
852890

@@ -860,7 +898,7 @@ impl PartialOrd<GStringPtr> for str {
860898
impl PartialOrd<GStringPtr> for GStr {
861899
#[inline]
862900
fn partial_cmp(&self, other: &GStringPtr) -> Option<std::cmp::Ordering> {
863-
Some(self.cmp(other.to_gstr()))
901+
Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) })
864902
}
865903
}
866904

@@ -871,10 +909,38 @@ impl PartialOrd<str> for GStringPtr {
871909
}
872910
}
873911

912+
impl PartialOrd<&str> for GStringPtr {
913+
#[inline]
914+
fn partial_cmp(&self, other: &&str) -> Option<std::cmp::Ordering> {
915+
Some(self.to_str().cmp(other))
916+
}
917+
}
918+
874919
impl PartialOrd<GStr> for GStringPtr {
875920
#[inline]
876921
fn partial_cmp(&self, other: &GStr) -> Option<std::cmp::Ordering> {
877-
Some(self.to_gstr().cmp(other))
922+
Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) })
923+
}
924+
}
925+
926+
impl PartialOrd<&GStr> for GStringPtr {
927+
#[inline]
928+
fn partial_cmp(&self, other: &&GStr) -> Option<std::cmp::Ordering> {
929+
Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) })
930+
}
931+
}
932+
933+
impl PartialOrd<GStringPtr> for &str {
934+
#[inline]
935+
fn partial_cmp(&self, other: &GStringPtr) -> Option<std::cmp::Ordering> {
936+
Some(self.cmp(&other.to_str()))
937+
}
938+
}
939+
940+
impl PartialOrd<GStringPtr> for &GStr {
941+
#[inline]
942+
fn partial_cmp(&self, other: &GStringPtr) -> Option<std::cmp::Ordering> {
943+
Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) })
878944
}
879945
}
880946

0 commit comments

Comments
 (0)