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#include <algorithm>
30#include <iterator>
31#include <string>
32#include <platform_lib_log_util.h>
33#include <ClientIndex.h>
34#include <IDataItemObserver.h>
35#include <DataItemId.h>
36
37using namespace std;
38using namespace loc_core;
39
40template <typename CT, typename DIT>
41inline ClientIndex <CT,DIT> :: ClientIndex () {}
42
43template <typename CT, typename DIT>
44inline ClientIndex <CT,DIT> :: ~ClientIndex () {}
45
46template <typename CT, typename DIT>
47bool ClientIndex <CT,DIT> :: isSubscribedClient (CT client) {
48    bool result = false;
49    ENTRY_LOG ();
50    typename map < CT, list <DIT> > :: iterator it =
51        mDataItemsPerClientMap.find (client);
52    if (it != mDataItemsPerClientMap.end ()) {
53        result = true;
54    }
55    EXIT_LOG_WITH_ERROR ("%d",result);
56    return result;
57}
58
59template <typename CT, typename DIT>
60void ClientIndex <CT,DIT> :: getSubscribedList (CT client, list <DIT> & out) {
61    ENTRY_LOG ();
62    typename map < CT, list <DIT> > :: iterator it =
63        mDataItemsPerClientMap.find (client);
64    if (it != mDataItemsPerClientMap.end ()) {
65        out = it->second;
66    }
67    EXIT_LOG_WITH_ERROR ("%d",0);
68}
69
70template <typename CT, typename DIT>
71int ClientIndex <CT,DIT> :: remove (CT client) {
72    int result = 0;
73    ENTRY_LOG ();
74    mDataItemsPerClientMap.erase (client);
75    EXIT_LOG_WITH_ERROR ("%d",result);
76    return result;
77}
78
79template <typename CT, typename DIT>
80void ClientIndex <CT,DIT> :: remove (const list <DIT> & r, list <CT> & out) {
81    ENTRY_LOG ();
82    typename map < CT, list <DIT> > :: iterator dicIter =
83        mDataItemsPerClientMap.begin ();
84    while (dicIter != mDataItemsPerClientMap.end()) {
85        typename list <DIT> :: const_iterator it = r.begin ();
86        for (; it != r.end (); ++it) {
87            typename list <DIT> :: iterator iter =
88                find (dicIter->second.begin (), dicIter->second.end (), *it);
89            if (iter != dicIter->second.end ()) {
90                dicIter->second.erase (iter);
91            }
92        }
93        if (dicIter->second.empty ()) {
94            out.push_back (dicIter->first);
95            // Post-increment operator increases the iterator but returns the
96            // prevous one that will be invalidated by erase()
97            mDataItemsPerClientMap.erase (dicIter++);
98        } else {
99            ++dicIter;
100        }
101    }
102    EXIT_LOG_WITH_ERROR ("%d",0);
103}
104
105template <typename CT, typename DIT>
106void ClientIndex <CT,DIT> :: remove
107(
108    CT client,
109    const list <DIT> & r,
110    list <DIT> & out
111)
112{
113    ENTRY_LOG ();
114    typename map < CT, list <DIT> > :: iterator dicIter =
115        mDataItemsPerClientMap.find (client);
116    if (dicIter != mDataItemsPerClientMap.end ()) {
117        set_intersection (dicIter->second.begin (), dicIter->second.end (),
118                         r.begin (), r.end (),
119                         inserter (out,out.begin ()));
120        if (!out.empty ()) {
121            typename list <DIT> :: iterator it = out.begin ();
122            for (; it != out.end (); ++it) {
123                dicIter->second.erase (find (dicIter->second.begin (),
124                                            dicIter->second.end (),
125                                            *it));
126            }
127        }
128        if (dicIter->second.empty ()) {
129            mDataItemsPerClientMap.erase (dicIter);
130            EXIT_LOG_WITH_ERROR ("%d",0);
131        }
132    }
133    EXIT_LOG_WITH_ERROR ("%d",0);
134}
135
136template <typename CT, typename DIT>
137void ClientIndex <CT,DIT> :: add
138(
139    CT client,
140    const list <DIT> & l,
141    list <DIT> & out
142)
143{
144    ENTRY_LOG ();
145    list <DIT> difference;
146    typename map < CT, list <DIT> > :: iterator dicIter =
147        mDataItemsPerClientMap.find (client);
148    if (dicIter != mDataItemsPerClientMap.end ()) {
149        set_difference (l.begin (), l.end (),
150                       dicIter->second.begin (), dicIter->second.end (),
151                       inserter (difference,difference.begin ()));
152        if (!difference.empty ()) {
153            difference.sort ();
154            out = difference;
155            dicIter->second.merge (difference);
156            dicIter->second.unique ();
157        }
158    } else {
159        out = l;
160        pair < CT, list <DIT> > dicnpair (client, out);
161        mDataItemsPerClientMap.insert (dicnpair);
162    }
163    EXIT_LOG_WITH_ERROR ("%d",0);
164}
165
166// Explicit instantiation must occur in same namespace where class is defined
167namespace loc_core
168{
169  template class ClientIndex <IDataItemObserver *, DataItemId>;
170  template class ClientIndex <string, DataItemId>;
171}
172