@@ -100,6 +100,34 @@ ly_version_proj_str(void)
100100 return LY_PROJ_VERSION ;
101101}
102102
103+ /**
104+ * @brief Callback for comparing two pattern records.
105+ */
106+ static ly_bool
107+ ly_ctx_ht_pattern_equal_cb (void * val1_p , void * val2_p , ly_bool UNUSED (mod ), void * UNUSED (cb_data ))
108+ {
109+ struct ly_pattern_ht_rec * val1 = val1_p ;
110+ struct ly_pattern_ht_rec * val2 = val2_p ;
111+
112+ /* compare the pattern strings, if they match we can use the stored
113+ * serialized value to create the pcre2 code for the pattern */
114+ return !strcmp (val1 -> pattern , val2 -> pattern );
115+ }
116+
117+ /**
118+ * @brief Callback for freeing a pattern record.
119+ */
120+ static void
121+ ly_ctx_ht_pattern_free_cb (void * val_p )
122+ {
123+ struct ly_pattern_ht_rec * val = val_p ;
124+
125+ if (val -> serialized_pattern ) {
126+ /* free the pcode */
127+ pcre2_serialize_free (val -> serialized_pattern );
128+ }
129+ }
130+
103131/**
104132 * @brief Remove private context data from the sized array and free its contents.
105133 *
@@ -369,34 +397,6 @@ ly_ctx_data_dict_get(const struct ly_ctx *ctx)
369397 return shared_data ? shared_data -> data_dict : NULL ;
370398}
371399
372- /**
373- * @brief Callback for comparing two pattern records.
374- */
375- static ly_bool
376- ly_ctx_ht_pattern_equal_cb (void * val1_p , void * val2_p , ly_bool UNUSED (mod ), void * UNUSED (cb_data ))
377- {
378- struct ly_pattern_ht_rec * val1 = val1_p ;
379- struct ly_pattern_ht_rec * val2 = val2_p ;
380-
381- /* compare the pattern strings, if they match we can use the stored
382- * serialized value to create the pcre2 code for the pattern */
383- return !strcmp (val1 -> pattern , val2 -> pattern );
384- }
385-
386- /**
387- * @brief Callback for freeing a pattern record.
388- */
389- static void
390- ly_ctx_ht_pattern_free_cb (void * val_p )
391- {
392- struct ly_pattern_ht_rec * val = val_p ;
393-
394- if (val -> serialized_pattern ) {
395- /* free the pcode */
396- pcre2_serialize_free (val -> serialized_pattern );
397- }
398- }
399-
400400LY_ERR
401401ly_ctx_data_add (const struct ly_ctx * ctx )
402402{
@@ -454,7 +454,6 @@ ly_ctx_data_del(const struct ly_ctx *ctx)
454454{
455455 struct ly_ctx_private_data * private_data ;
456456 struct ly_ctx_shared_data * shared_data ;
457- LY_ARRAY_COUNT_TYPE idx ;
458457
459458 /* WR LOCK */
460459 pthread_rwlock_wrlock (& ly_ctx_data_rwlock );
@@ -547,57 +546,101 @@ ly_pcode_deserialize(const uint8_t *serialized_code, pcre2_code **pcode)
547546 return LY_SUCCESS ;
548547}
549548
550- LY_ERR
551- ly_ctx_get_or_create_pattern_code (const struct ly_ctx * ctx , const char * pattern , pcre2_code * * pcode )
549+ /**
550+ * @brief Get a compiled PCRE2 pattern code from the context's pattern hash table.
551+ *
552+ * @param[in] ctx Context to get the pattern code from.
553+ * @param[in] pattern Pattern string to search for.
554+ * @param[in] pattern_ht Pattern hash table to search in.
555+ * @param[out] pcode Optional compiled pattern code, must be freed by the caller.
556+ * If NULL, the function only checks if the pattern exists in the hash table.
557+ * @return LY_SUCCESS on success, LY_ENOTFOUND if the pattern was not found,
558+ * other LY_ERR values on error.
559+ */
560+ static LY_ERR
561+ _ly_ctx_get_pattern_code (const struct ly_ctx * ctx , const char * pattern ,
562+ struct ly_ht * pattern_ht , pcre2_code * * pcode )
552563{
553- LY_ERR ret = LY_SUCCESS ;
554- struct ly_ctx_shared_data * ctx_data ;
564+ LY_ERR rc = LY_SUCCESS ;
555565 uint32_t hash ;
556566 struct ly_pattern_ht_rec rec = {0 }, * found_rec = NULL ;
557- pcre2_code * pcode_tmp = NULL ;
558- uint8_t * serialized_pcode = NULL ;
559-
560- assert (ctx && pattern );
561567
562- ctx_data = ly_ctx_shared_data_get (ctx );
563- LY_CHECK_RET (!ctx_data , LY_EINT );
568+ assert (ctx && pattern && pattern_ht );
564569
565- /* try to find the record */
570+ /* use the pattern as a key */
566571 rec .pattern = pattern ;
567572 rec .serialized_pattern = NULL ;
568573 hash = lyht_hash (pattern , strlen (pattern ));
569574
570- if (!lyht_find (ctx_data -> pattern_ht , & rec , hash , (void * * )& found_rec )) {
575+ /* try to find the record */
576+ LY_CHECK_GOTO (rc = lyht_find (pattern_ht , & rec , hash , (void * * )& found_rec ), cleanup );
577+
578+ if (pcode ) {
571579 /* found it, deserialize the pcode */
572- LY_CHECK_GOTO (ret = ly_pcode_deserialize (found_rec -> serialized_pattern , & pcode_tmp ), cleanup );
573- if (pcode ) {
574- * pcode = pcode_tmp ;
575- pcode_tmp = NULL ;
576- }
580+ LY_CHECK_GOTO (rc = ly_pcode_deserialize (found_rec -> serialized_pattern , pcode ), cleanup );
581+ }
582+
583+ cleanup :
584+ return rc ;
585+ }
586+
587+ LY_ERR
588+ ly_ctx_get_pattern_code (const struct ly_ctx * ctx , const char * pattern , pcre2_code * * pcode )
589+ {
590+ LY_ERR rc = LY_SUCCESS ;
591+ struct ly_ctx_shared_data * ctx_data ;
592+
593+ ctx_data = ly_ctx_shared_data_get (ctx );
594+ LY_CHECK_RET (!ctx_data , LY_EINT );
595+
596+ rc = _ly_ctx_get_pattern_code (ctx , pattern , ctx_data -> pattern_ht , pcode );
597+ if (rc ) {
598+ LOGERR (ctx , rc , "Failed to get pattern code for \"%s\"." , pattern );
599+ }
600+
601+ return rc ;
602+ }
603+
604+ LY_ERR
605+ ly_ctx_compile_and_cache_pattern_code (const struct ly_ctx * ctx , const char * pattern )
606+ {
607+ LY_ERR rc = LY_SUCCESS ;
608+ struct ly_ctx_shared_data * ctx_data ;
609+ uint8_t * serialized_pcode = NULL ;
610+ pcre2_code * pcode_tmp = NULL ;
611+ struct ly_pattern_ht_rec rec = {0 };
612+ uint32_t hash ;
613+
614+ ctx_data = ly_ctx_shared_data_get (ctx );
615+ LY_CHECK_RET (!ctx_data , LY_EINT );
616+
617+ /* check for existing pattern code */
618+ rc = _ly_ctx_get_pattern_code (ctx , pattern , ctx_data -> pattern_ht , NULL );
619+ LY_CHECK_GOTO (rc && (rc != LY_ENOTFOUND ), cleanup );
620+ if (!rc ) {
621+ /* pattern is already compiled and stored, nothing to do */
577622 goto cleanup ;
578623 }
579624
580625 /* record not found, we need to compile the pattern and insert it */
581- LY_CHECK_GOTO (ret = lys_compile_type_pattern_check (ctx , pattern , & pcode_tmp ), cleanup );
626+ LY_CHECK_GOTO (rc = lys_compile_type_pattern_check (ctx , pattern , & pcode_tmp ), cleanup );
582627
583628 /* serialize the pcode */
584- LY_CHECK_GOTO (ret = ly_pcode_serialize (pcode_tmp , & serialized_pcode ), cleanup );
585- rec .serialized_pattern = serialized_pcode ;
629+ LY_CHECK_GOTO (rc = ly_pcode_serialize (pcode_tmp , & serialized_pcode ), cleanup );
586630
587631 /* insert the record */
588- LY_CHECK_GOTO (ret = lyht_insert_no_check (ctx_data -> pattern_ht , & rec , hash , (void * * )& found_rec ), cleanup );
632+ hash = lyht_hash (pattern , strlen (pattern ));
633+ rec .pattern = pattern ;
634+ rec .serialized_pattern = serialized_pcode ;
635+ LY_CHECK_GOTO (rc = lyht_insert_no_check (ctx_data -> pattern_ht , & rec , hash , NULL ), cleanup );
589636
590- if (pcode ) {
591- /* transfer pcode ownership to the caller */
592- * pcode = pcode_tmp ;
593- pcode_tmp = NULL ;
594- }
637+ /* dont free the serialized pcode, it is now owned by the record in the hash table */
595638 serialized_pcode = NULL ;
596639
597640cleanup :
598641 pcre2_code_free (pcode_tmp );
599642 pcre2_serialize_free (serialized_pcode );
600- return ret ;
643+ return rc ;
601644}
602645
603646void *
0 commit comments