From 333c3e0d80f7e1e341d2928217a688d7cae4a197 Mon Sep 17 00:00:00 2001 From: Jens Alfke Date: Fri, 16 Feb 2024 14:31:05 -0800 Subject: [PATCH] Expose additional FLKeyPath API Exposed existing methods of the internal KeyPath class to the C & C++ APIs, so we can use them in LiteCore code that uses the public API: FLKeyPath_GetCount FLKeyPath_NewEmpty FLKeyPath_AddProperty FLKeyPath_AddIndex FLKeyPath_AddComponents FLKeyPath_DropComponents --- API/fleece/FLKeyPath.h | 42 +++++++++++++++++++++++++++++++-------- API/fleece/Fleece.hh | 38 +++++++++++++++++++++++++++-------- Fleece/API_Impl/Fleece.cc | 33 ++++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 18 deletions(-) diff --git a/API/fleece/FLKeyPath.h b/API/fleece/FLKeyPath.h index cd91877e..01fc4334 100644 --- a/API/fleece/FLKeyPath.h +++ b/API/fleece/FLKeyPath.h @@ -46,20 +46,20 @@ extern "C" { /** Creates a new FLKeyPath object by compiling a path specifier string. */ NODISCARD FLEECE_PUBLIC FLKeyPath FL_NULLABLE FLKeyPath_New(FLSlice specifier, - FLError* FL_NULLABLE outError) FLAPI; + FLError* FL_NULLABLE outError) FLAPI; /** Frees a compiled FLKeyPath object. (It's ok to pass NULL.) */ FLEECE_PUBLIC void FLKeyPath_Free(FLKeyPath FL_NULLABLE) FLAPI; /** Evaluates a compiled key-path for a given Fleece root object. */ NODISCARD FLEECE_PUBLIC FLValue FL_NULLABLE FLKeyPath_Eval(FLKeyPath, - FLValue root) FLAPI; + FLValue root) FLAPI; /** Evaluates a key-path from a specifier string, for a given Fleece root object. If you only need to evaluate the path once, this is a bit faster than creating an FLKeyPath object, evaluating, then freeing it. */ NODISCARD FLEECE_PUBLIC FLValue FL_NULLABLE FLKeyPath_EvalOnce(FLSlice specifier, FLValue root, - FLError* FL_NULLABLE outError) FLAPI; + FLError* FL_NULLABLE outError) FLAPI; /** Returns a path in string form. */ NODISCARD FLEECE_PUBLIC FLStringResult FLKeyPath_ToString(FLKeyPath path) FLAPI; @@ -67,11 +67,37 @@ extern "C" { /** Equality test. */ FLEECE_PUBLIC bool FLKeyPath_Equals(FLKeyPath path1, FLKeyPath path2) FLAPI; - /** Returns an element of a path, either a key or an array index. */ - FLEECE_PUBLIC bool FLKeyPath_GetElement(FLKeyPath, - size_t i, - FLSlice *outDictKey, - int32_t *outArrayIndex) FLAPI; + /** The number of path components. */ + FLEECE_PUBLIC size_t FLKeyPath_GetCount(FLKeyPath) FLAPI; + + /** Returns an element of a path, either a key or an array index. + @param path The path to examine. + @param i The index of the component to examine. + @param outDictKey On return this will be the property name, or a null slice + if this component is an array index. + @param outArrayIndex On return this will be the array index, + or 0 if this component is a property. + @returns True on success, false if there is no such component. */ + FLEECE_PUBLIC bool FLKeyPath_GetElement(FLKeyPath path, + size_t i, + FLSlice *outDictKey, + int32_t *outArrayIndex) FLAPI; + + /** Creates a new _empty_ FLKeyPath, for the purpose of adding components to it. */ + NODISCARD FLEECE_PUBLIC FLKeyPath FL_NULLABLE FLKeyPath_NewEmpty(void) FLAPI; + + /** Appends a single property/key component to a path. The string should not be escaped. */ + FLEECE_PUBLIC void FLKeyPath_AddProperty(FLKeyPath, FLString property) FLAPI; + + /** Appends a single array index component to a path. */ + FLEECE_PUBLIC void FLKeyPath_AddIndex(FLKeyPath, int index) FLAPI; + + /** Appends one or more components, encoded as a specifier like the one passed to FLKeyPath_New. */ + NODISCARD FLEECE_PUBLIC bool FLKeyPath_AddComponents(FLKeyPath, FLString specifier, + FLError* FL_NULLABLE outError) FLAPI; + + /** Removes the first `n` components. */ + FLEECE_PUBLIC void FLKeyPath_DropComponents(FLKeyPath, size_t n) FLAPI; /** @} */ diff --git a/API/fleece/Fleece.hh b/API/fleece/Fleece.hh index 801890d2..03e4c938 100644 --- a/API/fleece/Fleece.hh +++ b/API/fleece/Fleece.hh @@ -17,6 +17,7 @@ #include "Fleece.h" #endif #include "slice.hh" +#include #include #include @@ -255,7 +256,8 @@ namespace fleece { property name (but not yet in the middle of a name.) */ class KeyPath { public: - KeyPath(slice_NONNULL spec, FLError* FL_NULLABLE err) :_path(FLKeyPath_New(spec, err)) { } + KeyPath() :_path(FLKeyPath_NewEmpty()) { } + KeyPath(slice_NONNULL spec, FLError* FL_NULLABLE err) :_path(FLKeyPath_New(spec, err)) { } ~KeyPath() {FLKeyPath_Free(_path);} KeyPath(KeyPath &&kp) :_path(kp._path) {kp._path = nullptr;} @@ -264,27 +266,37 @@ namespace fleece { KeyPath(const KeyPath &kp) :KeyPath(std::string(kp), nullptr) { } + explicit operator bool() const {return _path != nullptr;} operator FLKeyPath FL_NONNULL () const {return _path;} - Value eval(Value root) const { - return FLKeyPath_Eval(_path, root); - } + size_t count() const {return FLKeyPath_GetCount(_path);} + + inline std::pair get(size_t i) const; + + Value eval(Value root) const {return FLKeyPath_Eval(_path, root);} static Value eval(slice_NONNULL specifier, Value root, FLError* FL_NULLABLE error) { return FLKeyPath_EvalOnce(specifier, root, error); } - explicit operator std::string() const { - return std::string(alloc_slice(FLKeyPath_ToString(_path))); - } + alloc_slice toString() const {return FLKeyPath_ToString(_path);} + explicit operator std::string() const {return std::string(toString());} bool operator== (const KeyPath &kp) const {return FLKeyPath_Equals(_path, kp._path);} + + void addProperty(slice key) {FLKeyPath_AddProperty(_path, key);} + void addIndex(int index) {FLKeyPath_AddIndex(_path, index);} + bool addComponents(slice components, FLError* FL_NULLABLE err) { + return FLKeyPath_AddComponents(_path, components, err); + } + void dropComponents(size_t n) {FLKeyPath_DropComponents(_path, n);} + private: KeyPath& operator=(const KeyPath&) =delete; friend class Value; - FLKeyPath _path; + FLKeyPath FL_NULLABLE _path; }; @@ -596,6 +608,16 @@ namespace fleece { template<> inline void Encoder::keyref::operator= (bool value) {_enc.writeKey(_key); _enc.writeBool(value);} + inline std::pair KeyPath::get(size_t i) const { + FLSlice key = {}; + int32_t index = 0; + if (FLKeyPath_GetElement(_path, i, &key, &index)) + return {key, index}; + else + throw std::domain_error("invalid KeyPath index"); + } + + inline Doc Doc::fromJSON(slice_NONNULL json, FLError * FL_NULLABLE outError) { return Doc(FLDoc_FromJSON(json, outError), false); } diff --git a/Fleece/API_Impl/Fleece.cc b/Fleece/API_Impl/Fleece.cc index d5ff9a10..a3a50869 100644 --- a/Fleece/API_Impl/Fleece.cc +++ b/Fleece/API_Impl/Fleece.cc @@ -555,7 +555,7 @@ FLSliceResult FLDeepIterator_GetJSONPointer(FLDeepIterator i) FLAPI { FLKeyPath FL_NULLABLE FLKeyPath_New(FLSlice specifier, FLError* FL_NULLABLE outError) FLAPI { try { - return new Path((std::string)(slice)specifier); + return new Path(specifier); } catchError(outError) return nullptr; } @@ -570,7 +570,7 @@ FLValue FL_NULLABLE FLKeyPath_Eval(FLKeyPath path, FLValue root) FLAPI { FLValue FL_NULLABLE FLKeyPath_EvalOnce(FLSlice specifier, FLValue root, FLError * FL_NULLABLE outError) FLAPI { try { - return Path::eval((std::string)(slice)specifier, root); + return Path::eval(specifier, root); } catchError(outError) return nullptr; } @@ -583,6 +583,10 @@ bool FLKeyPath_Equals(FLKeyPath path1, FLKeyPath path2) FLAPI { return *path1 == *path2; } +size_t FLKeyPath_GetCount(FLKeyPath path) FLAPI { + return path->size(); +} + bool FLKeyPath_GetElement(FLKeyPath path, size_t i, FLSlice *outKey, int32_t *outIndex) FLAPI { if (i >= path->size()) return false; @@ -592,6 +596,31 @@ bool FLKeyPath_GetElement(FLKeyPath path, size_t i, FLSlice *outKey, int32_t *ou return true; } +FLKeyPath FL_NULLABLE FLKeyPath_NewEmpty(void) FLAPI { + return new Path(); +} + +void FLKeyPath_AddProperty(FLKeyPath path, FLString property) FLAPI { + if (property.size > 0) + path->addProperty(property); +} + +void FLKeyPath_AddIndex(FLKeyPath path, int index) FLAPI { + path->addIndex(index); +} + +bool FLKeyPath_AddComponents(FLKeyPath path, FLString specifier, FLError* FL_NULLABLE outError) FLAPI { + try { + path->addComponents(specifier); + return true; + } catchError(outError) + return false; +} + +void FLKeyPath_DropComponents(FLKeyPath path, size_t n) FLAPI { + path->drop(n); +} + #pragma mark - ENCODER: