Newer
Older
libj / include / j / util / array_list.hpp
/**
 * @file array_list.hpp
 * @brief J Library ArrayList ヘッダファイル。
 * @copyright  2001 - 2024  Nomura Kei
 * @depends
 *   j/lang/iterable.hpp
 */
#ifndef J_UTIL_ARRAY_LIST_HPP
#define J_UTIL_ARRAY_LIST_HPP

#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
#include <memory>

#include <j/lang/index_out_of_bounds_exception.hpp>
#include <j/util/iterator.hpp>
#include <j/util/list.hpp>

namespace j
{
    namespace util
    {

        template <typename T>
        class ArrayList : public List<T>, public j::lang::Object
        {
        public:
            ArrayList() = default;
            virtual ~ArrayList() = default;

            /**
             * このリスト内にある要素の数を返します。
             *
             * @return このリスト内の要素数
             */
            virtual int size() const override
            {
                return static_cast<int>(items.size());
            }

            /**
             * このリストに要素がない場合に true を返します。
             *
             * @return このリストに要素が含まれていない場合は true
             */
            virtual bool isEmpty() const override
            {
                return items.empty();
            }

            /**
             * 指定の要素がこのリストに含まれている場合に true を返します。
             *
             * @param このリスト内にあるかどうか判定される要素
             * @return 指定された要素がこのリスト内にある場合は true
             */
            virtual bool contains(const T &t) const override
            {
                return (std::find(items.begin(), items.end(), t) != items.end());
            }

            /**
             * 指定された要素がこのリスト内で最初に検出された位置のインデックスを返します。
             * 指定された要素がこのリストにない場合は -1 を返します。
             *
             * @param t 検索する要素
             * @return 指定された要素がリスト内で最初に検出された位置のインデックス。その要素がリストにない場合は -1。
             */
            virtual int indexOf(const T &t) const override
            {
                auto it = std::find(items.begin(), items.end(), t);
                if (it != items.end())
                {
                    return std::distance(items.begin(), it);
                }
                return -1;
            }

            /**
             * 指定された要素がこのリスト内で最後に検出された位置のインデックスを返します。
             * 指定された要素がこのリストにない場合は -1 を返します。
             *
             * @param t 検索する要素
             * @return 指定された要素がリスト内で最後に検出された位置のインデックス。その要素がリストにない場合は -1。
             */
            virtual int lastIndexOf(const T &t) const override
            {
                auto it = std::find(items.rbegin(), items.rend(), t);
                if (it != items.rend())
                {
                    return std::distance(items.begin(), it.base()) - 1;
                }
                return -1;
            }

            /**
             * このリスト内の指定された位置にある要素を返します。
             *
             * @param index 返される要素のインデックス
             * @return このリスト内の指定された位置にある要素
             */
            virtual T &get(int index) override
            {
                if ((index < 0) || (index >= size()))
                {
                    std::ostringstream ss;
                    ss << "index out of range: " << index;
                    throw j::lang::IndexOutOfBoundsException(ss.str());
                }
                return items[index];
            }

            /**
             * このリストの指定された位置にある要素を、指定された要素で置き換えます。
             *
             * @param index 置換される要素のインデックス
             * @param t 指定された位置に格納される要素
             * @return 指定された位置に以前あった要素
             */
            virtual T set(int index, const T &t) override
            {
                if ((index < 0) || (index >= size()))
                {
                    std::ostringstream ss;
                    ss << "index out of range: " << index;
                    throw j::lang::IndexOutOfBoundsException(ss.str());
                }
                T oldItem = std::move(items[index]);
                items[index] = t;
                return oldItem;
            }

            /**
             * このリストの最後に、指定された要素を追加します。
             *
             * @param t このリストに追加される要素
             * @return true
             */
            virtual bool add(const T &t) override
            {
                items.push_back(t);
                return true;
            }

            /**
             * このリスト内の指定された位置に指定された要素を挿入します。
             * その位置とそれ以降に要素があればそれらを右に移動させ、各要素のインデックスに1を加えます。
             *
             * @param index 指定の要素が挿入される位置のインデックス
             * @param t 挿入される要素
             */
            virtual void add(int index, const T &t) override
            {
                if ((index < 0) || (index > size()))
                {
                    std::ostringstream ss;
                    ss << "index out of range: " << index;
                    throw j::lang::IndexOutOfBoundsException(ss.str());
                }
                items.insert(items.begin() + index, t);
            }

            /**
             * このリストの指定された位置にある要素を削除します。
             * 後続の要素は左に移動します(インデックス値から1を減算)。
             *
             * @param index 削除される要素のインデックス
             * @return リストから削除した要素
             */
            virtual T remove(int index) override
            {
                if ((index < 0) || (index >= size()))
                {
                    std::ostringstream ss;
                    ss << "index out of range: " << index;
                    throw j::lang::IndexOutOfBoundsException(ss.str());
                }
                T removedItem = items[index];
                items.erase(items.begin() + index);
                return removedItem;
            }

            /**
             * 指定された要素がこのリストにあれば、その最初のものをリストから削除します。
             * その要素がリストになり場合、変更はありません。
             * 指定された要素がこのリストに含まれていた場合は true を返します。
             *
             * @param t このリストから削除される要素
             * @return 指定された要素がこのリストに含まれていた場合は true
             */
            virtual bool remove(const T &t) override
            {
                auto it = std::find(items.begin(), items.end(), t);
                if (it != items.end())
                {
                    items.erase(it);
                    return true;
                }
                return false;
            }

            /**
             * このリストからすべての要素を削除します。
             * この呼出しが戻ると、このリストは空になります。
             */
            virtual void clear() override
            {
                items.clear();
            }

            std::unique_ptr<Iterator<T>> iterator() const override
            {
                return std::make_unique<Iterator<T>>(items.begin(), items.end());
            }

            Iterator<T> begin()
            {
                return Iterator<T>(items.begin(), items.end());
            }

            Iterator<T> end()
            {
                return Iterator<T>(items.end(), items.end());
            }

            virtual j::lang::String toString()
            {
                std::stringstream oss;
                bool isFirst = true;
                oss << "[";
                for (const auto &e : items)
                {
                    if (!isFirst)
                    {
                        oss << ", ";
                    }
                    oss << e;
                    isFirst = false;
                }
                oss << "]";
                return j::lang::String(oss.str());
            }

        private:
            std::vector<T> items;
        };

    } // namespace util
} // namespace j

#endif // J_UTIL_ARRAY_LIST_HPP