Skip to content

Commit

Permalink
Some slice code cleanup, removing C++11/C++14 shims
Browse files Browse the repository at this point in the history
- Added `data()` and `size_bytes()` methods to slice types, like those
  in std::span. (Can't add `size()` because it conflicts with a data
  member.) This is an incremental step toward moving to `span`, or at
  least making the `buf` and `size` fields private.
- Likewise, added `data()`, `size_bytes()` to FLSlice and
  FLSliceResult, as well as `empty()` and `operator bool`.
- Removed obsolete `sliceHash`.
- Removed conditional support for `std::string_view`, unnecessary
  since we require C++17.
- Removed `constexpr14` which was only useful when we supported C++11.
- Added default initializers to slice member variables instead of
  initializing in the default constructor.
- Use `= default` for default constructors.
  • Loading branch information
snej committed Aug 5, 2024
1 parent d46257c commit a8a9a47
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 86 deletions.
12 changes: 0 additions & 12 deletions API/fleece/CompilerSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,18 +153,6 @@
#endif


// `constexpr14` is for uses of `constexpr` that are valid in C++14 but not earlier.
// In constexpr functions this includes `if`, `for`, `while` statements; or multiple `return`s.
// The macro expands to `constexpr` in C++14 or later, otherwise to nothing.
#ifdef __cplusplus
#if __cplusplus >= 201400L || _MSVC_LANG >= 201400L
#define constexpr14 constexpr
#else
#define constexpr14
#endif
#endif // __cplusplus


// STEPOVER is for trivial little glue functions that are annoying to step into in the debugger
// on the way to the function you _do_ want to step into. Examples are RefCounted's operator->,
// or slice constructors. Suppressing debug info for those functions means the debugger
Expand Down
18 changes: 12 additions & 6 deletions API/fleece/FLSlice.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ typedef struct FLSlice {
size_t size;

#ifdef __cplusplus
explicit operator bool() const noexcept FLPURE {return buf != nullptr;}
explicit operator std::string() const {return std::string((char*)buf, size);}
constexpr const void* FL_NULLABLE data() const noexcept FLPURE {return buf;}
constexpr size_t size_bytes() const noexcept FLPURE {return size;} // compatibility with std::span
constexpr bool empty() const noexcept FLPURE {return size == 0;}
constexpr explicit operator bool() const noexcept FLPURE {return buf != nullptr;}
explicit operator std::string() const {return std::string((char*)buf, size);}
#endif
} FLSlice;

Expand All @@ -65,8 +68,11 @@ struct NODISCARD FLSliceResult {
size_t size;

#ifdef __cplusplus
explicit operator bool() const noexcept FLPURE {return buf != nullptr;}
explicit operator FLSlice () const {return {buf, size};}
constexpr const void* FL_NULLABLE data() const noexcept FLPURE {return buf;}
constexpr size_t size_bytes() const noexcept FLPURE {return size;} // compatibility with std::span
constexpr bool empty() const noexcept FLPURE {return size == 0;}
constexpr explicit operator bool() const noexcept FLPURE {return buf != nullptr;}
constexpr explicit operator FLSlice () const {return {buf, size};}
inline explicit operator std::string() const;
#endif
};
Expand Down Expand Up @@ -123,7 +129,7 @@ static inline void FLMemCpy(void* FL_NULLABLE dst, const void* FL_NULLABLE src,
It's OK to pass NULL; this returns an empty slice.
\note If the string is a literal, it's more efficient to use \ref FLSTR instead.
\note Performance is O(n) with the length of the string, since it has to call `strlen`. */
static inline FLSlice FLStr(const char* FL_NULLABLE str) FLAPI {
static inline FLSlice FLStr(const char* FL_NULLABLE str LIFETIMEBOUND) FLAPI {
FLSlice foo = { str, str ? strlen(str) : 0 };
return foo;
}
Expand Down Expand Up @@ -185,7 +191,7 @@ static inline void FLSliceResult_Release(FLSliceResult s) FLAPI {
}

/** Type-casts a FLSliceResult to FLSlice, since C doesn't know it's a subclass. */
static inline FLSlice FLSliceResult_AsSlice(FLSliceResult sr) {
static inline FLSlice FLSliceResult_AsSlice(FLSliceResult sr LIFETIMEBOUND) {
FLSlice ret;
memcpy(&ret, &sr, sizeof(ret));
return ret;
Expand Down
99 changes: 32 additions & 67 deletions API/fleece/slice.hh
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@

#include "FLSlice.h"
#include <algorithm> // for std::min()
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h> // for fputs()
#include <string.h> // for memcpy(), memcmp()
#include <cstddef>
#include <cstdlib>
#include <cstdio> // for fputs()
#include <cstring> // for memcpy(), memcmp()
#include <string>
#include <string_view>

#ifndef assert
# include <assert.h>
# include <cassert>
#endif
# ifndef assert_precondition
# define assert_precondition(e) assert(e)
Expand All @@ -39,14 +40,6 @@
# endif
#endif

// Figure out whether and how string_view is available
#ifdef __has_include
# if __has_include(<string_view>)
# include <string_view>
# define SLICE_SUPPORTS_STRING_VIEW
# endif
#endif


// Utility for using slice with printf-style formatting.
// Use "%.*" in the format string; then for the corresponding argument put FMTSLICE(theslice).
Expand All @@ -62,24 +55,20 @@ namespace fleece {
struct alloc_slice;
struct nullslice_t;

#ifdef SLICE_SUPPORTS_STRING_VIEW
using string_view = std::string_view; // create typedef with correct namespace
#endif

#ifdef __APPLE__
using CFStringRef = const struct ::__CFString *;
using CFDataRef = const struct ::__CFData *;
#endif

/** Adds a byte offset to a pointer. */
template <typename T>
FLCONST constexpr14 inline const T* FL_NONNULL offsetby(const T * FL_NONNULL t, ptrdiff_t offset) noexcept {
FLCONST constexpr inline const T* FL_NONNULL offsetby(const T * FL_NONNULL t, ptrdiff_t offset) noexcept {
return (const T*)((uint8_t*)t + offset);
}

/** Adds a byte offset to a pointer. */
template <typename T>
FLCONST constexpr14 inline T* FL_NONNULL offsetby(T * FL_NONNULL t, ptrdiff_t offset) noexcept {
FLCONST constexpr inline T* FL_NONNULL offsetby(T * FL_NONNULL t, ptrdiff_t offset) noexcept {
return (T*)((uint8_t*)t + offset);
}

Expand Down Expand Up @@ -110,13 +99,14 @@ namespace fleece {
ownership: it manages a ref-counted heap-allocated buffer.
* Instances are immutable: `buf` and `size` cannot be changed. The `slice` subclass
changes this.
* The memory pointed to cannot be modified through this class. `slice` has some
methods that allow writes. */
* The memory pointed to cannot be modified through this class. */
struct pure_slice {
const void* FL_NULLABLE const buf;
size_t const size;
const void* FL_NULLABLE const buf = nullptr;
size_t const size = 0;

constexpr const void* data() const noexcept FLPURE {return buf;} //like std::span
constexpr size_t size_bytes() const noexcept FLPURE {return size;} //like std::span

pure_slice(const pure_slice &) noexcept = default;
/// True if the slice's length is zero.
bool empty() const noexcept FLPURE {return size == 0;}

Expand Down Expand Up @@ -178,11 +168,9 @@ namespace fleece {
/// Copies my contents to memory starting at `dst`, using `memcpy`.
void copyTo(void *dst) const noexcept {FLMemCpy(dst, buf, size);}

/// Returns new malloc'ed slice containing same data. Call free() on it when done.
inline slice copy() const;

// String conversions:

operator std::string_view() const noexcept STEPOVER {return {(const char*)buf, size};}
explicit operator std::string() const {return std::string((const char*)buf, size);}
std::string asString() const {return (std::string)*this;}

Expand All @@ -192,15 +180,8 @@ namespace fleece {
will not overflow the buffer. Returns false if the slice was truncated. */
inline bool toCString(char *buf, size_t bufSize) const noexcept;

// FLSlice interoperability:
constexpr operator FLSlice () const noexcept {return {buf, size};}

#ifdef SLICE_SUPPORTS_STRING_VIEW
// std::string_view interoperability:
constexpr pure_slice(string_view str) noexcept :pure_slice(str.data(), str.length()) {}
operator string_view() const noexcept STEPOVER {return string_view((const char*)buf, size);}
#endif

#ifdef __APPLE__
// Implementations in slice+CoreFoundation.cc and slice+ObjC.mm
explicit pure_slice(CFDataRef FL_NULLABLE data) noexcept;
Expand All @@ -220,15 +201,18 @@ namespace fleece {

constexpr pure_slice(std::nullptr_t) noexcept :pure_slice() {}
constexpr pure_slice(const char* FL_NULLABLE str) noexcept :buf(str), size(_strlen(str)) {}
pure_slice(const std::string& str LIFETIMEBOUND) noexcept :buf(&str[0]), size(str.size()) {}
pure_slice(const std::string& str LIFETIMEBOUND) noexcept :buf(str.data()), size(str.size()) {}
constexpr pure_slice(std::string_view str) noexcept :pure_slice(str.data(), str.length()) {}

// Raw memory allocation. These throw std::bad_alloc on failure.
RETURNS_NONNULL inline static void* newBytes(size_t sz);
template <typename T> RETURNS_NONNULL
static inline T* FL_NONNULL reallocBytes(T* FL_NULLABLE bytes, size_t newSz);
// Returns new malloc'ed slice containing same data. Call free() on it when done.
inline slice copy() const;

protected:
constexpr pure_slice() noexcept :buf(nullptr), size(0) {}
constexpr pure_slice() noexcept = default;
inline constexpr pure_slice(const void* FL_NULLABLE b, size_t s) noexcept;

inline void setBuf(const void *b) noexcept;
Expand Down Expand Up @@ -259,13 +243,14 @@ namespace fleece {
* `buf` may be NULL, but only if `size` is zero; this is called `nullslice`.
* `size` may be zero with a non-NULL `buf`; that's called an "empty slice". */
struct slice : public pure_slice {
constexpr slice() noexcept STEPOVER :pure_slice() {}
constexpr slice() noexcept STEPOVER = default;
constexpr slice(std::nullptr_t) noexcept STEPOVER :pure_slice() {}
inline constexpr slice(nullslice_t) noexcept STEPOVER;
constexpr slice(const void* FL_NULLABLE b LIFETIMEBOUND, size_t s) noexcept STEPOVER :pure_slice(b, s) {}
inline constexpr slice(const void* start LIFETIMEBOUND, const void* end) noexcept STEPOVER;
inline slice(const alloc_slice& LIFETIMEBOUND) noexcept STEPOVER;

constexpr slice(std::string_view str) noexcept STEPOVER :pure_slice(str) {}
slice(const std::string& str LIFETIMEBOUND) noexcept STEPOVER :pure_slice(str) {}
constexpr slice(const char* FL_NULLABLE str LIFETIMEBOUND) noexcept STEPOVER :pure_slice(str) {}

Expand Down Expand Up @@ -294,10 +279,6 @@ namespace fleece {
explicit slice(const FLSliceResult &sr LIFETIMEBOUND) STEPOVER :pure_slice(sr.buf, sr.size) { }
slice& operator= (FLHeapSlice s) noexcept {set(s.buf, s.size); return *this;} // disambiguation

#ifdef SLICE_SUPPORTS_STRING_VIEW
constexpr slice(string_view str) noexcept STEPOVER :pure_slice(str) {}
#endif

#ifdef __APPLE__
explicit slice(CFDataRef data) noexcept :pure_slice(data) {}
# ifdef __OBJC__
Expand All @@ -309,10 +290,10 @@ namespace fleece {

/** An awkwardly unrelated struct for when the bytes need to be writeable. */
struct mutable_slice {
void* FL_NULLABLE buf;
size_t size;
void* FL_NULLABLE buf = nullptr;
size_t size = 0;

constexpr mutable_slice() noexcept :buf(nullptr), size(0) {}
constexpr mutable_slice() noexcept = default;
explicit constexpr mutable_slice(pure_slice s) noexcept :buf((void*)s.buf), size(s.size) {}
constexpr mutable_slice(void* FL_NULLABLE b, size_t s) noexcept :buf(b), size(s) {}
constexpr mutable_slice(void* b, void* e) noexcept :buf(b),
Expand Down Expand Up @@ -343,16 +324,16 @@ namespace fleece {

/** A \ref slice that owns a heap-allocated, ref-counted block of memory. */
struct [[nodiscard]] alloc_slice : public pure_slice {
constexpr alloc_slice() noexcept STEPOVER {}
constexpr alloc_slice() noexcept STEPOVER = default;
constexpr alloc_slice(std::nullptr_t) noexcept STEPOVER {}
constexpr alloc_slice(nullslice_t) noexcept STEPOVER {}

inline explicit alloc_slice(size_t sz) STEPOVER;

alloc_slice(const void* FL_NULLABLE b, size_t s) :alloc_slice(slice(b, s)) {}
alloc_slice(const void* start,
const void* end) :alloc_slice(slice(start, end)) {}
alloc_slice(const void* start, const void* end) :alloc_slice(slice(start, end)) {}
explicit alloc_slice(const char* FL_NULLABLE str) :alloc_slice(slice(str)) {}
explicit alloc_slice(std::string_view str) STEPOVER :alloc_slice(slice(str)) {}
explicit alloc_slice(const std::string &str) :alloc_slice(slice(str)) {}

inline explicit alloc_slice(pure_slice s) STEPOVER;
Expand All @@ -374,11 +355,12 @@ namespace fleece {
inline static alloc_slice nullPaddedString(pure_slice);

alloc_slice& operator= (pure_slice s) {return *this = alloc_slice(s);}
alloc_slice& operator= (FLSlice s) {return operator=(slice(s.buf,s.size));}
alloc_slice& operator= (FLSlice s) {return *this = alloc_slice(s);}
alloc_slice& operator= (std::nullptr_t) noexcept {reset(); return *this;}

// disambiguation:
alloc_slice& operator= (const char *str) {*this = (slice)str; return *this;}
alloc_slice& operator=(std::string_view str) {*this = (slice)str; return *this;}
alloc_slice& operator= (const std::string &str) {*this = (slice)str; return *this;}

/// Releases and clears; same as assigning `nullslice`.
Expand All @@ -405,12 +387,6 @@ namespace fleece {
alloc_slice& operator= (FLHeapSlice) noexcept;
operator FLHeapSlice () const noexcept {return {buf, size};}

// std::string_view interoperability:
#ifdef SLICE_SUPPORTS_STRING_VIEW
explicit alloc_slice(string_view str) STEPOVER :alloc_slice(slice(str)) {}
alloc_slice& operator=(string_view str) {*this = (slice)str; return *this;}
#endif

// CFData / CFString / NSData / NSString interoperability:
#ifdef __APPLE__
// Implementations in slice+CoreFoundation.cc and slice+ObjC.mm
Expand Down Expand Up @@ -445,17 +421,14 @@ namespace fleece {
constexpr slice_NONNULL(slice s) :slice_NONNULL(s.buf, s.size) {}
constexpr slice_NONNULL(FLSlice s) :slice_NONNULL(s.buf,s.size) {}
constexpr slice_NONNULL(const char *str NONNULL) :slice(str) {}
slice_NONNULL(alloc_slice s) :slice_NONNULL(s.buf,s.size) {}
slice_NONNULL(const alloc_slice& s) :slice_NONNULL(s.buf,s.size) {}
slice_NONNULL(const std::string &str) :slice_NONNULL(str.data(),str.size()) {}
#ifdef SLICE_SUPPORTS_STRING_VIEW
slice_NONNULL(string_view str) :slice_NONNULL(str.data(),str.size()) {}
#endif
slice_NONNULL(std::string_view str) :slice_NONNULL(str.data(),str.size()) {}
slice_NONNULL(std::nullptr_t) =delete;
slice_NONNULL(nullslice_t) =delete;
};



#ifdef __APPLE__
/** A slice holding the UTF-8 data of an NSString. If possible, it gets a pointer directly into
the NSString in O(1) time -- so don't modify or release the NSString while this is in scope.
Expand All @@ -475,14 +448,6 @@ namespace fleece {
#endif


/** Functor class for hashing the contents of a slice.
\note The below declarations of `std::hash` usually make it unnecessary to use this. */
struct sliceHash {
std::size_t operator() (pure_slice const& s) const {return s.hash();}
};



#pragma mark - PURE_SLICE METHOD BODIES:


Expand Down
2 changes: 1 addition & 1 deletion Fleece/Integration/MDict.hh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace fleece {
public:
using MValue = MValue<Native>;
using MCollection = MCollection<Native>;
using MapType = std::unordered_map<slice, MValue, fleece::sliceHash>;
using MapType = std::unordered_map<slice, MValue>;

/** Constructs an empty MDict not connected to any existing Fleece Dict. */
MDict() :MCollection() { }
Expand Down

0 comments on commit a8a9a47

Please sign in to comment.