* - 0 if we allocated a new attribute.
* - -1 on failure.
*/
-#define pair_update_request(_attr, _da) fr_pair_update_by_da(request->request_ctx, _attr, _da)
+#define pair_update_request(_attr, _da) fr_pair_update_by_da_parent(request->request_ctx, _attr, _da)
/** Return or allocate a fr_pair_t in the reply list
*
* - 0 if we allocated a new attribute.
* - -1 on failure.
*/
-#define pair_update_reply(_attr, _da) fr_pair_update_by_da(request->reply_ctx, _attr, _da)
+#define pair_update_reply(_attr, _da) fr_pair_update_by_da_parent(request->reply_ctx, _attr, _da)
/** Return or allocate a fr_pair_t in the control list
*
* - 0 if we allocated a new attribute.
* - -1 on failure.
*/
-#define pair_update_control(_attr, _da) fr_pair_update_by_da(request->control_ctx, _attr, _da)
+#define pair_update_control(_attr, _da) fr_pair_update_by_da_parent(request->control_ctx, _attr, _da)
/** Return or allocate a fr_pair_t in the session_state list
*
* - 0 if we allocated a new attribute.
* - -1 on failure.
*/
-#define pair_update_session_state(_attr, _da) fr_pair_update_by_da(request->session_state_ctx, _attr, _da)
+#define pair_update_session_state(_attr, _da) fr_pair_update_by_da_parent(request->session_state_ctx, _attr, _da)
/** Delete one or move fr_pair_t in a list
*
* - 0 if we allocated a new attribute.
* - -1 on failure.
*/
-int fr_pair_update_by_da(fr_pair_t *parent, fr_pair_t **out,
- fr_dict_attr_t const *da)
+int fr_pair_update_by_da_parent(fr_pair_t *parent, fr_pair_t **out,
+ fr_dict_attr_t const *da)
{
- fr_pair_t *vp;
+ fr_pair_t *vp = NULL;
+ fr_da_stack_t da_stack;
+ fr_dict_attr_t const **find;
+ TALLOC_CTX *pair_ctx = parent;
+ fr_pair_list_t *list = &parent->vp_group;
- vp = fr_pair_find_by_da_idx(&parent->vp_group, da, 0);
- if (vp) {
- PAIR_VERIFY_WITH_LIST(&parent->vp_group, vp);
- if (out) *out = vp;
- return 1;
- }
+ /*
+ * Fast path for non-nested attributes
+ */
+ if (da->depth <= 1) {
+ vp = fr_pair_find_by_da(list, NULL, da);
+ if (vp) {
+ *out = vp;
+ return 1;
+ }
- vp = fr_pair_afrom_da(parent, da);
- if (unlikely(!vp)) {
- if (out) *out = NULL;
- return -1;
+ return fr_pair_append_by_da(parent, out, list, da);
}
- fr_pair_append(&parent->vp_group, vp);
- if (out) *out = vp;
+ fr_proto_da_stack_build(&da_stack, da);
+ find = &da_stack.da[0];
- return 0;
+ /*
+ * Walk down the da stack looking for candidate parent
+ * attributes and then allocating the leaf.
+ */
+ while (true) {
+ fr_assert((*find)->depth <= da->depth);
+
+ /*
+ * We're not at the leaf, look for a potential parent
+ */
+ if ((*find) != da) vp = fr_pair_find_by_da(list, NULL, *find);
+
+ /*
+ * Nothing found, create the pair
+ */
+ if (!vp) {
+ if (fr_pair_append_by_da(pair_ctx, &vp, list, *find) < 0) {
+ *out = NULL;
+ return -1;
+ }
+ }
+
+ /*
+ * We're at the leaf, return
+ */
+ if ((*find) == da) {
+ *out = vp;
+ return 0;
+ }
+
+ /*
+ * Prepare for next level
+ */
+ list = &vp->vp_group;
+ pair_ctx = vp;
+ vp = NULL;
+ find++;
+ }
}
/** Delete matching pairs from the specified list
int fr_pair_append_by_da_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list,
fr_dict_attr_t const *da) CC_HINT(nonnull(3,4));
-int fr_pair_update_by_da(fr_pair_t *parent, fr_pair_t **out,
- fr_dict_attr_t const *da) CC_HINT(nonnull(1,3));
+int fr_pair_update_by_da_parent(fr_pair_t *parent, fr_pair_t **out,
+ fr_dict_attr_t const *da) CC_HINT(nonnull(1,3));
int fr_pair_delete_by_da(fr_pair_list_t *head, fr_dict_attr_t const *da) CC_HINT(nonnull);
fr_pair_list_free(&local_pairs);
}
-static void test_fr_pair_update_by_da(void)
+static void test_fr_pair_update_by_da_parent(void)
{
fr_pair_t *vp, *group;
TEST_CHECK((group = fr_pair_afrom_da(autofree, fr_dict_attr_test_group)) != NULL);
TEST_CASE("Update Add using fr_pair_prepend_by_da()");
- TEST_CHECK(fr_pair_update_by_da(group, &vp, fr_dict_attr_test_uint32) == 0); /* attribute doesn't exist in this group */
+ TEST_CHECK(fr_pair_update_by_da_parent(group, &vp, fr_dict_attr_test_uint32) == 0); /* attribute doesn't exist in this group */
vp->vp_uint32 = 54321;
TEST_CASE("Expected fr_dict_attr_test_uint32 (vp->vp_uint32 == 54321)");
{ "fr_pair_prepend_by_da", test_fr_pair_prepend_by_da },
{ "fr_pair_append_by_da_parent", test_fr_pair_append_by_da_parent },
{ "fr_pair_delete_by_child_num", test_fr_pair_delete_by_child_num },
- { "fr_pair_update_by_da", test_fr_pair_update_by_da },
+ { "fr_pair_update_by_da_parent", test_fr_pair_update_by_da_parent },
{ "fr_pair_delete", test_fr_pair_delete },
{ "fr_pair_delete_by_da", test_fr_pair_delete_by_da },