1/* Copyright (C) 2021 Free Software Foundation, Inc.
2   Contributed by Oracle.
3
4   This file is part of GNU Binutils.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, 51 Franklin Street - Fifth Floor, Boston,
19   MA 02110-1301, USA.  */
20
21#ifndef _DbeSyncMap_h
22#define _DbeSyncMap_h
23
24#include "DbeLock.h"
25#include "DbeLinkList.h"
26#include "vec.h"
27
28typedef unsigned long hash_ty;
29
30template <class ITEM> class DbeSyncMap : public DbeLock
31{
32public:
33  DbeSyncMap (int _chunkSize = DefaultChunkSize);
34  virtual ~DbeSyncMap ();
35  void reset ();
36  ITEM *get (const char *nm, int64_t chksum);
37  ITEM *sync_create_item (const char *nm, int64_t chksum);
38  ITEM *get (const char *nm, const char *path, DbeFile *df);
39  ITEM *sync_create_item (const char *nm, const char *path, DbeFile *df);
40  virtual void dump ();
41
42  Vector<ITEM *> *
43  values ()
44  {
45    return items;
46  };
47
48private:
49  hash_ty hash (const char *key);
50
51  DbeLinkList<ITEM *> **chunk;
52  Vector<ITEM *> *items;
53  long chunkSize;
54
55  enum
56  {
57    DefaultChunkSize = 1024
58  };
59};
60
61template <class ITEM>
62DbeSyncMap<ITEM>::DbeSyncMap (int _chunkSize)
63{
64  chunkSize = _chunkSize;
65  chunk = new DbeLinkList<ITEM *> * [chunkSize];
66  for (long i = 0; i < chunkSize; i++)
67    chunk[i] = NULL;
68  items = new Vector<ITEM *>(512);
69}
70
71template <class ITEM>
72DbeSyncMap<ITEM>::~DbeSyncMap ()
73{
74  for (long i = 0; i < chunkSize; i++)
75    Destroy (chunk[i]);
76  delete[] chunk;
77  delete items;
78}
79
80template <class ITEM>
81void
82DbeSyncMap<ITEM>::reset ()
83{
84  for (long i = 0; i < chunkSize; i++)
85    {
86      Destroy (chunk[i]);
87      chunk[i] = NULL;
88    }
89  items->reset ();
90}
91
92template <class ITEM>
93ITEM *
94DbeSyncMap<ITEM>::get (const char *nm, int64_t chksum)
95{
96  hash_ty h = hash (nm);
97  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
98    {
99      ITEM *item = dl->get_item ();
100      if (item->compare (nm, chksum))
101	return item;
102    }
103  return NULL;
104}
105
106template <class ITEM>
107hash_ty
108DbeSyncMap<ITEM>::hash (const char *key)
109{
110  return (hash_ty) (crc64 (key, strlen (key)) % chunkSize);
111}
112
113template <class ITEM>
114ITEM *
115DbeSyncMap<ITEM>::sync_create_item (const char *nm, int64_t chksum)
116{
117  hash_ty h = hash (nm);
118  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
119    {
120      ITEM *item = dl->get_item ();
121      if (item->compare (nm, chksum))
122	return item;
123    }
124  aquireLock ();
125  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
126    {
127      ITEM *item = dl->get_item ();
128      if (item->compare (nm, chksum))
129	{
130	  releaseLock ();
131	  return item;
132	}
133    }
134  ITEM *item = ITEM::create_item (nm, chksum);
135  DbeLinkList<ITEM *> *dl = new DbeLinkList<ITEM *>(item);
136  dl->set_next (chunk[h]);
137  chunk[h] = dl;
138  items->append (item);
139  releaseLock ();
140  return item;
141}
142
143template <class ITEM>
144ITEM *
145DbeSyncMap<ITEM>::get (const char *nm, const char *path, DbeFile *df)
146{
147  int mask = 1 + (path != NULL ? 2 : 0) + (df != NULL ? 4 : 0);
148  hash_ty h = hash (nm);
149  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
150    {
151      ITEM *item = dl->get_item ();
152      if (mask == item->compare (nm, path, df))
153	return item;
154    }
155  return NULL;
156}
157
158template <class ITEM>
159ITEM *
160DbeSyncMap<ITEM>::sync_create_item (const char *nm, const char *path, DbeFile *df)
161{
162  int mask = CMP_PATH;
163  if (path != NULL)
164    mask += CMP_RUNTIMEPATH;
165  if (df != NULL)
166    mask += CMP_CHKSUM;
167  hash_ty h = hash (nm);
168  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
169    {
170      ITEM *item = dl->get_item ();
171      if (mask == item->compare (nm, path, df))
172	return item;
173    }
174  aquireLock ();
175  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
176    {
177      ITEM *item = dl->get_item ();
178      if (mask == item->compare (nm, path, df))
179	{
180	  releaseLock ();
181	  return item;
182	}
183    }
184  ITEM *item = ITEM::create_item (nm, path, df);
185  DbeLinkList<ITEM *> *dl = new DbeLinkList<ITEM *>(item);
186  dl->set_next (chunk[h]);
187  chunk[h] = dl;
188  items->append (item);
189  releaseLock ();
190  return item;
191}
192
193template <class ITEM>
194void
195DbeSyncMap<ITEM>::dump ()
196{
197  Dprintf (1, NTXT ("\nDbeSyncMap::dump:  vals=%ld\n"), (long) VecSize (items));
198  int tot = 0;
199  int max_cnt = 0;
200  for (long i = 0; i < chunkSize; i++)
201    {
202      DbeLinkList<ITEM *> *lp = chunk[i];
203      if (lp)
204	{
205	  int cnt = 0;
206	  for (DbeLinkList<ITEM *> *lp1 = lp; lp1; lp1 = lp1->get_next ())
207	    cnt++;
208	  tot += cnt;
209	  if (max_cnt < cnt)
210	    max_cnt = cnt;
211	  cnt = 1;
212	  for (DbeLinkList<ITEM *> *lp1 = lp; lp1; lp1 = lp1->get_next ())
213	    {
214	      ITEM *p = lp1->get_item ();
215	      Dprintf (1, NTXT ("      %2d %s\n"), cnt, p->get_name ());
216	      cnt++;
217	    }
218	}
219    }
220  Dprintf (1, NTXT ("\nDbeSyncMap::dump: vals=%ld max_cnt=%d tot=%d\n"),
221	   (long) VecSize (items), max_cnt, tot);
222}
223
224#endif /* _DbeSyncMap_h */
225