/* Copyright (C) 2021-2026 Free Software Foundation, Inc.
   Contributed by Oracle.

   This file is part of GNU Binutils.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

#ifndef _DBE_DEFAULTMAP2D_H
#define _DBE_DEFAULTMAP2D_H

#include <assert.h>
#include <vec.h>
#include <DefaultMap.h>
#include <IntervalMap.h>
#include <Map2D.h>

/*
 *	Default Map2D implementation.
 *
 *    Default Map2D is a cartesian product of two default Maps.
 */

template <typename Key1_t, typename Key2_t, typename Value_t>
class DefaultMap2D : public Map2D<Key1_t, Key2_t, Value_t>
{
public:
  DefaultMap2D ();
  DefaultMap2D (typename Map2D<Key1_t, Key2_t, Value_t>::MapType _type);
  ~DefaultMap2D ();
  void put (Key1_t key1, Key2_t key2, Value_t val);
  Value_t get (Key1_t key1, Key2_t key2);
  Value_t get (Key1_t key1, Key2_t key2,
	       typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel);
  Value_t remove (Key1_t, Key2_t);

private:
  typename Map2D<Key1_t, Key2_t, Value_t>::MapType type;
  Map<Key1_t, Map<Key2_t, Value_t>*> *map1;
  Vector<Map<Key2_t, Value_t>*> *map2list;
};

template <typename Key1_t, typename Key2_t, typename Value_t>
DefaultMap2D<Key1_t, Key2_t, Value_t>::DefaultMap2D ()
{
  type = Map2D<Key1_t, Key2_t, Value_t>::Default;
  map1 = new DefaultMap<Key1_t, Map<Key2_t, Value_t>*>;
  map2list = new Vector<Map<Key2_t, Value_t>*>;
}

template <typename Key1_t, typename Key2_t, typename Value_t>
DefaultMap2D<Key1_t, Key2_t, Value_t>::DefaultMap2D (
			 typename Map2D<Key1_t, Key2_t, Value_t>::MapType _type)
{
  type = _type;
  map1 = new DefaultMap<Key1_t, Map<Key2_t, Value_t>*>;
  map2list = new Vector<Map<Key2_t, Value_t>*>;
}

template <typename Key1_t, typename Key2_t, typename Value_t>
DefaultMap2D<Key1_t, Key2_t, Value_t>::~DefaultMap2D ()
{
  map2list->destroy ();
  delete map2list;
  delete map1;
}

template <typename Key1_t, typename Key2_t, typename Value_t>
void
DefaultMap2D<Key1_t, Key2_t, Value_t>::put (Key1_t key1, Key2_t key2, Value_t val)
{
  Map<Key2_t, Value_t> *map2 = map1->get (key1);
  if (map2 == NULL)
    {
      if (type == Map2D<Key1_t, Key2_t, Value_t>::Interval)
	map2 = new IntervalMap<Key2_t, Value_t>;
      else
	map2 = new DefaultMap<Key2_t, Value_t>;
      map2list->append (map2);
      map1->put (key1, map2);
    }
  map2->put (key2, val);
}

template <typename Key1_t, typename Key2_t, typename Value_t>
Value_t
DefaultMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2)
{
  Map<Key2_t, Value_t> *map2 = map1->get (key1);
  if (map2 == NULL)
    return (Value_t) 0;
  return map2->get (key2);
}

template <typename Key1_t, typename Key2_t, typename Value_t>
Value_t
DefaultMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2,
			  typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel)
{
  Map<Key2_t, Value_t> *map2 = map1->get (key1);
  if (map2 == NULL)
    return (Value_t) 0;
  typename Map<Key2_t, Value_t>::Relation rel2;
  switch (rel)
    {
    case Map2D<Key1_t, Key2_t, Value_t>::REL_EQLT:
      rel2 = map2->REL_LT;
      break;
    case Map2D<Key1_t, Key2_t, Value_t>::REL_EQLE:
      rel2 = map2->REL_LE;
      break;
    case Map2D<Key1_t, Key2_t, Value_t>::REL_EQGE:
      rel2 = map2->REL_GE;
      break;
    case Map2D<Key1_t, Key2_t, Value_t>::REL_EQGT:
      rel2 = map2->REL_GT;
      break;
    default:
      rel2 = map2->REL_EQ;
      break;
    }
  return map2->get (key2, rel2);
}

template <typename Key1_t, typename Key2_t, typename Value_t>
Value_t
DefaultMap2D<Key1_t, Key2_t, Value_t>::remove (Key1_t, Key2_t)
{
  // Not implemented
  if (1)
    assert (0);
  return (Value_t) 0;
}

#endif
