51ccd8c31ce851601a8866af8fd7a480395443b8
[ircu2.10.12-pk.git] / libs / dbprim / st_add.c
1 /*
2 ** Copyright (C) 2002 by Kevin L. Mitchell <klmitch@mit.edu>
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Library General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 ** Library General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Library General Public
15 ** License along with this library; if not, write to the Free
16 ** Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
17 ** MA 02111-1307, USA
18 **
19 ** @(#)$Id$
20 */
21 #include <errno.h>
22
23 #include "dbprim.h"
24 #include "dbprim_int.h"
25
26 RCSTAG("@(#)$Id$");
27
28 /** \ingroup dbprim_smat
29  * \brief Add an entry to a sparse matrix.
30  *
31  * This function adds an entry to a sparse matrix.  The entry is
32  * referenced in three different places, thus the complex set of
33  * arguments.  This function will allocate a #smat_entry_t and return
34  * it through the \c entry_p result parameter.
35  *
36  * \param table A pointer to a #smat_table_t.
37  * \param entry_p
38  *              A pointer to a pointer to a #smat_entry_t.  This is a
39  *              result parameter.  If \c NULL is passed, the addition
40  *              will be performed and an appropriate error code
41  *              returned.
42  * \param head1 A pointer to a #smat_head_t representing a
43  *              #SMAT_LOC_FIRST sparse matrix list.
44  * \param loc1  A #link_loc_t indicating where the entry should be
45  *              added for \c head1.
46  * \param ent1  A pointer to a #smat_entry_t describing another
47  *              element in the list represented by \c head1 if \p loc1
48  *              is #LINK_LOC_BEFORE or #LINK_LOC_AFTER.
49  * \param head2 A pointer to a #smat_head_t representing a
50  *              #SMAT_LOC_SECOND sparse matrix list.
51  * \param loc2  A #link_loc_t indicating where the entry should be
52  *              added for \c head2.
53  * \param ent2  A pointer to a #smat_entry_t describing another
54  *              element in the list represented by \c head2 if \p loc2
55  *              is #LINK_LOC_BEFORE or #LINK_LOC_AFTER.
56  *
57  * \retval DB_ERR_BADARGS       An argument was invalid.
58  * \retval DB_ERR_BUSY          One of the arguments is already in the
59  *                              table.
60  * \retval DB_ERR_FROZEN        The table is currently frozen.
61  * \retval DB_ERR_NOTABLE       The bucket table has not been
62  *                              allocated and automatic growth is not
63  *                              enabled.
64  * \retval DB_ERR_WRONGTABLE    One of the arguments was not in the
65  *                              proper table or list.
66  * \retval DB_ERR_UNUSED        One of the \c ent arguments is not
67  *                              presently in a list.
68  * \retval DB_ERR_UNRECOVERABLE An unrecoverable error occurred while
69  *                              resizing the table.
70  * \retval ENOMEM               No memory could be allocated for the
71  *                              #smat_entry_t structure.
72  */
73 unsigned long
74 st_add(smat_table_t *table, smat_entry_t **entry_p,
75        smat_head_t *head1, link_loc_t loc1, smat_entry_t *ent1,
76        smat_head_t *head2, link_loc_t loc2, smat_entry_t *ent2)
77 {
78   smat_entry_t *se;
79   unsigned long retval = 0;
80   unsigned int freeflags = 0;
81   db_key_t key;
82
83   initialize_dbpr_error_table(); /* initialize error table */
84
85   /* Verify arguments--like ll_add(), but has to account for two seperate
86    * linked lists
87    */
88   if (!st_verify(table) || !sh_verify(head1) || !sh_verify(head2) ||
89       head1->sh_elem != SMAT_LOC_FIRST || head2->sh_elem != SMAT_LOC_SECOND ||
90       (ent1 && !se_verify(ent1)) || (ent2 && !se_verify(ent2)) ||
91       ((loc1 == LINK_LOC_BEFORE || loc1 == LINK_LOC_AFTER) && !ent1) ||
92       ((loc2 == LINK_LOC_BEFORE || loc2 == LINK_LOC_AFTER) && !ent2))
93     return DB_ERR_BADARGS;
94
95   /* verify that everything's in the right tables... */
96   if ((head1->sh_table && head1->sh_table != table) ||
97       (head2->sh_table && head2->sh_table != table) ||
98       (ent1 && ent1->se_table != table) ||
99       (ent2 && ent2->se_table != table))
100     return DB_ERR_WRONGTABLE;
101
102   if (!(se = _smat_alloc())) /* get an entry object */
103     return ENOMEM;
104
105   freeflags |= ST_REM_FREE; /* entry has been allocated */
106
107   se->se_object[SMAT_LOC_FIRST] = sh_object(head1); /* set up the hash key */
108   se->se_object[SMAT_LOC_SECOND] = sh_object(head2);
109   dk_key(&key) = &se->se_object;
110   dk_len(&key) = 0;
111
112   /* add the element to the hash table first */
113   if ((retval = ht_add(&table->st_table, &se->se_hash, &key)))
114     goto error;
115
116   freeflags |= ST_REM_HASH; /* entry must be removed from hash table */
117
118   /* add the element to the first linked list */
119   if ((retval = ll_add(&head1->sh_head, &se->se_link[SMAT_LOC_FIRST], loc1,
120                        ent1 ? &ent1->se_link[SMAT_LOC_FIRST] : 0)))
121     goto error;
122
123   freeflags |= ST_REM_FIRST; /* entry must be removed from linked list 1 */
124
125   /* add the element to the second linked list */
126   if ((retval = ll_add(&head2->sh_head, &se->se_link[SMAT_LOC_SECOND], loc2,
127                        ent2 ? &ent2->se_link[SMAT_LOC_SECOND] : 0)))
128     goto error;
129
130   head1->sh_table = head2->sh_table = table; /* remember our table */
131   se->se_table = table;
132
133   if (!entry_p) /* user wants to know which entry it is */
134     *entry_p = se;
135
136   return 0; /* all done! */
137
138  error:
139   /* unlink entry from linked list 1 */
140   if ((freeflags & ST_REM_FIRST) &&
141       ll_remove(&head1->sh_head, &se->se_link[SMAT_LOC_FIRST]))
142     return DB_ERR_UNRECOVERABLE;
143
144   /* remove element from hash table */
145   if ((freeflags & ST_REM_HASH) && ht_remove(&table->st_table, &se->se_hash))
146     return DB_ERR_UNRECOVERABLE;
147
148   /* return element to free pool */
149   if (freeflags & ST_REM_FREE)
150     _smat_free(se);
151
152   return retval; /* return error */
153 }