1/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above
9 *       copyright notice, this list of conditions and the following
10 *       disclaimer in the documentation and/or other materials provided
11 *       with the distribution.
12 *     * Neither the name of The Linux Foundation, nor the names of its
13 *       contributors may be used to endorse or promote products derived
14 *       from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#include <string>
31#include <algorithm>
32#include <iterator>
33#include <DataItemIndex.h>
34#include <platform_lib_log_util.h>
35#include <IDataItemObserver.h>
36#include <DataItemId.h>
37
38using namespace std;
39using namespace loc_core;
40
41template <typename CT, typename DIT>
42inline DataItemIndex <CT,DIT> :: DataItemIndex () {}
43
44template <typename CT, typename DIT>
45inline DataItemIndex <CT,DIT> :: ~DataItemIndex () {}
46
47template <typename CT, typename DIT>
48void DataItemIndex <CT,DIT> :: getListOfSubscribedClients
49 (
50    DIT id,
51    list <CT> & out
52)
53{
54    typename map < DIT, list <CT> > :: iterator cdiIter =
55        mClientsPerDataItemMap.find (id);
56    if (cdiIter != mClientsPerDataItemMap.end ()) {
57        out = cdiIter->second;
58    }
59}
60
61
62template <typename CT, typename DIT>
63int DataItemIndex <CT,DIT> :: remove (DIT id) {
64    int result = 0;
65    ENTRY_LOG ();
66    mClientsPerDataItemMap.erase (id);
67    EXIT_LOG_WITH_ERROR ("%d",result);
68    return result;
69}
70
71template <typename CT, typename DIT>
72void DataItemIndex <CT,DIT> :: remove (const list <CT> & r, list <DIT> & out) {
73    ENTRY_LOG ();
74    typename map < DIT, list <CT> > :: iterator cdiIter =
75        mClientsPerDataItemMap.begin ();
76    while (cdiIter != mClientsPerDataItemMap.end()) {
77        typename list <CT> :: const_iterator it = r.begin ();
78        for (; it != r.end (); ++it) {
79            typename list <CT> :: iterator iter =
80                find
81                (
82                    cdiIter->second.begin (),
83                    cdiIter->second.end (),
84                    *it
85                );
86            if (iter != cdiIter->second.end ()) {
87                cdiIter->second.erase (iter);
88            }
89        }
90
91        if (cdiIter->second.empty ()) {
92            out.push_back (cdiIter->first);
93            // Post-increment operator increases the iterator but returns the
94            // prevous one that will be invalidated by erase()
95            mClientsPerDataItemMap.erase (cdiIter++);
96        } else {
97            ++cdiIter;
98        }
99    }
100    EXIT_LOG_WITH_ERROR ("%d",0);
101}
102
103template <typename CT, typename DIT>
104void DataItemIndex <CT,DIT> :: remove
105(
106    DIT id,
107    const list <CT> & r,
108    list <CT> & out
109)
110{
111    ENTRY_LOG ();
112
113    typename map < DIT, list <CT> > :: iterator cdiIter =
114        mClientsPerDataItemMap.find (id);
115    if (cdiIter != mClientsPerDataItemMap.end ()) {
116        set_intersection (cdiIter->second.begin (), cdiIter->second.end (),
117                         r.begin (), r.end (),
118                         inserter (out, out.begin ()));
119        if (!out.empty ()) {
120            typename list <CT> :: iterator it = out.begin ();
121            for (; it != out.end (); ++it) {
122                cdiIter->second.erase (find (cdiIter->second.begin (),
123                                            cdiIter->second.end (),
124                                            *it));
125            }
126        }
127        if (cdiIter->second.empty ()) {
128            mClientsPerDataItemMap.erase (cdiIter);
129            EXIT_LOG_WITH_ERROR ("%d",0);
130        }
131    }
132    EXIT_LOG_WITH_ERROR ("%d",0);
133}
134
135template <typename CT, typename DIT>
136void DataItemIndex <CT,DIT> :: add
137(
138    DIT id,
139    const list <CT> & l,
140    list <CT> & out
141)
142{
143    ENTRY_LOG ();
144    list <CT> difference;
145    typename map < DIT, list <CT> > :: iterator cdiIter =
146        mClientsPerDataItemMap.find (id);
147    if (cdiIter != mClientsPerDataItemMap.end ()) {
148        set_difference (l.begin (), l.end (),
149                       cdiIter->second.begin (), cdiIter->second.end (),
150                       inserter (difference, difference.begin ()));
151        if (!difference.empty ()) {
152            difference.sort ();
153            out = difference;
154            cdiIter->second.merge (difference);
155        }
156    } else {
157        out = l;
158        pair < DIT, list <CT> > cndipair (id, out);
159        mClientsPerDataItemMap.insert (cndipair);
160    }
161    EXIT_LOG_WITH_ERROR ("%d",0);
162}
163
164template <typename CT, typename DIT>
165void DataItemIndex <CT,DIT> :: add
166(
167    CT client,
168    const list <DIT> & l,
169    list <DIT> & out
170)
171{
172    ENTRY_LOG ();
173    typename map < DIT, list <CT> > :: iterator cdiIter;
174    typename list <DIT> :: const_iterator it = l.begin ();
175    for (; it != l.end (); ++it) {
176        cdiIter = mClientsPerDataItemMap.find (*it);
177        if (cdiIter == mClientsPerDataItemMap.end ()) {
178            out.push_back (*it);
179            pair < DIT, list <CT> > cndiPair (*it, list <CT> (1, client));
180            mClientsPerDataItemMap.insert (cndiPair);
181        } else {
182          typename list<CT> :: iterator clientIter =
183              find
184              (
185                cdiIter->second.begin (),
186                cdiIter->second.end (),
187                client
188              );
189            if (clientIter == cdiIter->second.end()) {
190              cdiIter->second.push_back (client);
191            }
192        }
193    }
194    EXIT_LOG_WITH_ERROR ("%d",0);
195}
196
197// Explicit instantiation must occur in same namespace where class is defined
198namespace loc_core
199{
200  template class DataItemIndex <IDataItemObserver *, DataItemId>;
201  template class DataItemIndex <string, DataItemId>;
202}
203