FieldDataDictionary.java

  1. /* Copyright 2002-2025 Bryan Cazabonne
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * Bryan Cazabonne licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.utils;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;

  20. import java.util.ArrayList;
  21. import java.util.Collections;
  22. import java.util.HashMap;
  23. import java.util.Iterator;
  24. import java.util.List;
  25. import java.util.Map;

  26. /** String → Object mapping, for small number of keys.
  27.  * <p>
  28.  * This class is a low overhead for a very small number of keys.
  29.  * It is based on simple array and string comparison. It plays
  30.  * the same role a {@code Map<String, Object>} but with reduced
  31.  * features and not intended for large number of keys. For such
  32.  * needs the regular {@code Map<String, Object>} should be preferred.
  33.  * </p>
  34.  *
  35.  * @see FieldArrayDictionary
  36.  * @author Bryan Cazabonne
  37.  * @since 13.0
  38.  */
  39. public class FieldDataDictionary<T extends CalculusFieldElement<T>> {

  40.     /** Default capacity. */
  41.     private static final int DEFAULT_INITIAL_CAPACITY = 4;

  42.     /** Field to which elements belong. */
  43.     private final Field<T> field;

  44.     /** Data container. */
  45.     private final List<Entry> data;

  46.     /** Constructor with {@link #DEFAULT_INITIAL_CAPACITY default initial capacity}.
  47.      * @param field field to which elements belong
  48.      */
  49.     public FieldDataDictionary(final Field<T> field) {
  50.         this(field, DEFAULT_INITIAL_CAPACITY);
  51.     }

  52.     /** Constructor from a map.
  53.      * @param field field to which the elements belong
  54.      * @param map map to use for initializing entries
  55.      */
  56.     public FieldDataDictionary(final Field<T> field, final Map<String, Object> map) {
  57.         this(field, map.size());
  58.         for (final Map.Entry<String, Object> entry : map.entrySet()) {
  59.             // we don't call put(key, value) to avoid the overhead of the unneeded call to remove(key)
  60.             data.add(new Entry(entry.getKey(), entry.getValue()));
  61.         }
  62.     }

  63.     /** Constructor from another dictionary.
  64.      * @param dictionary dictionary to use for initializing entries
  65.      */
  66.     public FieldDataDictionary(final FieldDataDictionary<T> dictionary) {
  67.         // take care to call dictionary.getData() and not use dictionary.data
  68.         this(dictionary.getField(), DEFAULT_INITIAL_CAPACITY + dictionary.getData().size());
  69.         for (final Entry entry : dictionary.getData()) {
  70.             // we don't call put(key, value) to avoid the overhead of the unneeded call to remove(key)
  71.             data.add(new Entry(entry.getKey(), entry.getValue()));
  72.         }
  73.     }

  74.     /** Constructor with specified capacity.
  75.      * @param field field to which elements belong
  76.      * @param initialCapacity initial capacity
  77.      */
  78.     public FieldDataDictionary(final Field<T> field, final int initialCapacity) {
  79.         this.data = new ArrayList<>(initialCapacity);
  80.         this.field = field;
  81.     }

  82.     /** Creates a "field" values dictionary.
  83.      * <p>
  84.      * Creates a DoubleArrayDictionary with all double[] values
  85.      * contained in the instance.
  86.      * </p>
  87.      * @return a double values dictionary
  88.      */
  89.     @SuppressWarnings("unchecked") // cast including generic type is checked and unitary tested
  90.     public FieldArrayDictionary<T> toFieldArrayDictionary() {
  91.         final FieldArrayDictionary<T> dictionary = new FieldArrayDictionary<>(field);
  92.         for (final Entry entry : data) {
  93.             if (entry.getValue() instanceof CalculusFieldElement[]) {
  94.                 dictionary.put(entry.getKey(), (T[]) entry.getValue());
  95.             }
  96.         }
  97.         return dictionary;
  98.     }

  99.     /** Create a map from the instance.
  100.      * <p>
  101.      * The map contains a copy of the instance data
  102.      * </p>
  103.      * @return copy of the dictionary, as an independent map
  104.      */
  105.     public Map<String, Object> toMap() {
  106.         final Map<String, Object> map = new HashMap<>(data.size());
  107.         for (final Entry entry : data) {
  108.             map.put(entry.getKey(), entry.getValue());
  109.         }
  110.         return map;
  111.     }

  112.     /** Remove all entries.
  113.      */
  114.     public void clear() {
  115.         data.clear();
  116.     }

  117.     /** Get the number of dictionary entries.
  118.      * @return number of dictionary entries
  119.      */
  120.     public int size() {
  121.         return data.size();
  122.     }

  123.     /** Add an entry.
  124.      * <p>
  125.      * If an entry with the same key already exists, it will be removed first.
  126.      * </p>
  127.      * <p>
  128.      * The new entry is always put at the end.
  129.      * </p>
  130.      * @param key entry key
  131.      * @param value entry value
  132.      */
  133.     public void put(final String key, final Object value) {
  134.         remove(key);
  135.         data.add(new Entry(key, value));
  136.     }

  137.     /** Put all the T[] entries from the map in the dictionary.
  138.      * @param map map to copy into the instance
  139.      */
  140.     public void putAllFields(final Map<String, T[]> map) {
  141.         for (final Map.Entry<String,  T[]> entry : map.entrySet()) {
  142.             put(entry.getKey(), entry.getValue());
  143.         }
  144.     }


  145.     /** Put all the entries from the map in the dictionary.
  146.      * @param map map to copy into the instance
  147.      */
  148.     public void putAll(final Map<String, Object> map) {
  149.         for (final Map.Entry<String, Object> entry : map.entrySet()) {
  150.             put(entry.getKey(), entry.getValue());
  151.         }
  152.     }

  153.     /** Put all the entries from another dictionary.
  154.      * @param dictionary dictionary to copy into the instance
  155.      */
  156.     public void putAll(final FieldDataDictionary<T> dictionary) {
  157.         for (final FieldDataDictionary<T>.Entry entry : dictionary.data) {
  158.             put(entry.getKey(), entry.getValue());
  159.         }
  160.     }

  161.     /** Get the value corresponding to a key.
  162.      * @param key entry key
  163.      * @return copy of the value corresponding to the key or null if key not present
  164.      */
  165.     public Object get(final String key) {
  166.         final FieldDataDictionary<T>.Entry entry = getEntry(key);
  167.         return entry == null ? null : entry.getValue();
  168.     }

  169.     /** Get a complete entry.
  170.      * @param key entry key
  171.      * @return entry with key if it exists, null otherwise
  172.      */
  173.     public Entry getEntry(final String key) {
  174.         for (final Entry entry : data) {
  175.             if (entry.getKey().equals(key)) {
  176.                 return entry;
  177.             }
  178.         }
  179.         return null;
  180.     }

  181.     /** Remove an entry.
  182.      * @param key key of the entry to remove
  183.      * @return true if an entry has been removed, false if the key was not present
  184.      */
  185.     public boolean remove(final String key) {
  186.         final Iterator<Entry> iterator = data.iterator();
  187.         while (iterator.hasNext()) {
  188.             if (iterator.next().getKey().equals(key)) {
  189.                 iterator.remove();
  190.                 return true;
  191.             }
  192.         }
  193.         return false;
  194.     }

  195.     /**
  196.      * Get an unmodifiable view of the dictionary entries.
  197.      *
  198.      * @return unmodifiable view of the dictionary entries
  199.      */
  200.     public List<Entry> getData() {
  201.         return Collections.unmodifiableList(data);
  202.     }

  203.     /**
  204.      * Get the field to which elements belong.
  205.      * @return the field to which elements belong
  206.      */
  207.     public Field<T> getField() {
  208.         return field;
  209.     }

  210.     /** Get a string representation of the dictionary.
  211.      * <p>
  212.      * This string representation is intended for improving displays in debuggers only.
  213.      * </p>
  214.      * @return string representation of the dictionary
  215.      */
  216.     @Override
  217.     public String toString() {
  218.         return DataDictionary.toString(toMap());
  219.     }

  220.     /** Entry in a dictionary. */
  221.     public class Entry {

  222.         /** Key. */
  223.         private final String key;

  224.         /** Value. */
  225.         private final Object value;

  226.         /** Simple constructor.
  227.          * @param key key
  228.          * @param value value
  229.          */
  230.         Entry(final String key, final Object value) {
  231.             this.key   = key;
  232.             this.value = value;
  233.         }

  234.         /** Get the entry key.
  235.          * @return entry key
  236.          */
  237.         public String getKey() {
  238.             return key;
  239.         }

  240.         /** Get the value.
  241.          * @return a copy of the value (independent from internal array if it is a double array)
  242.          */
  243.         @SuppressWarnings("unchecked")
  244.         public Object getValue() {
  245.             return value instanceof CalculusFieldElement[] ? ((T[]) value).clone() : value;
  246.         }

  247.         /** Increment the value with another scaled entry.
  248.          * <p>
  249.          * Each component {@code value[i]} will be replaced by {@code value[i] + factor * raw.value[i]}.
  250.          * </p>
  251.          * <p>
  252.          * For the sake of performance, no checks are done on arguments.
  253.          * </p>
  254.          * @param factor multiplicative factor for increment
  255.          * @param raw raw increment to be multiplied by {@code factor} and then added
  256.          */
  257.         @SuppressWarnings("unchecked")
  258.         public void scaledIncrement(final double factor, final FieldArrayDictionary<T>.Entry raw) {
  259.             if (value instanceof CalculusFieldElement[]) {
  260.                 for (int i = 0; i < raw.getValue().length; ++i) {
  261.                     ((T[]) value)[i] = ((T[]) value)[i].add(raw.getValue()[i].multiply(factor));
  262.                 }
  263.             }
  264.         }

  265.         /** Increment the value with another scaled entry.
  266.          * <p>
  267.          * Each component {@code value[i]} will be replaced by {@code value[i] + factor * raw.value[i]}.
  268.          * </p>
  269.          * <p>
  270.          * For the sake of performance, no checks are done on arguments.
  271.          * </p>
  272.          * @param factor multiplicative factor for increment
  273.          * @param raw raw increment to be multiplied by {@code factor} and then added
  274.          */
  275.         @SuppressWarnings("unchecked")
  276.         public void scaledIncrement(final T factor, final FieldArrayDictionary<T>.Entry raw) {
  277.             if (value instanceof CalculusFieldElement[]) {
  278.                 for (int i = 0; i < raw.getValue().length; ++i) {
  279.                     ((T[]) value)[i] = ((T[]) value)[i].add(raw.getValue()[i].multiply(factor));
  280.                 }
  281.             }
  282.         }

  283.     }

  284. }