mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:42:43 +00:00 
			
		
		
		
	 35c9aa7c05
			
		
	
	
		35c9aa7c05
		
	
	
	
	
		
			
			Now that the GC allocator is able to invoke Cell subclass constructors directly via friendship, we no longer need to keep them public. :^)
		
			
				
	
	
		
			119 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #include <AK/Concepts.h>
 | |
| #include <AK/HashMap.h>
 | |
| #include <AK/RedBlackTree.h>
 | |
| #include <LibJS/Runtime/GlobalObject.h>
 | |
| #include <LibJS/Runtime/Object.h>
 | |
| #include <LibJS/Runtime/Value.h>
 | |
| #include <LibJS/Runtime/ValueTraits.h>
 | |
| 
 | |
| namespace JS {
 | |
| 
 | |
| class Map : public Object {
 | |
|     JS_OBJECT(Map, Object);
 | |
| 
 | |
|     // NOTE: This awkwardness is due to Set using a Map internally.
 | |
|     friend class Set;
 | |
| 
 | |
| public:
 | |
|     static Map* create(Realm&);
 | |
| 
 | |
|     virtual ~Map() override = default;
 | |
| 
 | |
|     void map_clear();
 | |
|     bool map_remove(Value const&);
 | |
|     Optional<Value> map_get(Value const&) const;
 | |
|     bool map_has(Value const&) const;
 | |
|     void map_set(Value const&, Value);
 | |
|     size_t map_size() const;
 | |
| 
 | |
|     struct EndIterator {
 | |
|     };
 | |
| 
 | |
|     template<bool IsConst>
 | |
|     struct IteratorImpl {
 | |
|         bool is_end() const
 | |
|         {
 | |
|             return m_map.m_keys.begin_from(m_index).is_end()
 | |
|                 && m_map.m_keys.find_smallest_not_below_iterator(m_index).is_end();
 | |
|         }
 | |
| 
 | |
|         IteratorImpl& operator++()
 | |
|         {
 | |
|             ++m_index;
 | |
|             return *this;
 | |
|         }
 | |
| 
 | |
|         decltype(auto) operator*()
 | |
|         {
 | |
|             ensure_next_element();
 | |
|             return *m_map.m_entries.find(*m_map.m_keys.begin_from(m_index));
 | |
|         }
 | |
| 
 | |
|         decltype(auto) operator*() const
 | |
|         {
 | |
|             ensure_next_element();
 | |
|             return *m_map.m_entries.find(*m_map.m_keys.begin_from(m_index));
 | |
|         }
 | |
| 
 | |
|         bool operator==(IteratorImpl const& other) const { return m_index == other.m_index && &m_map == &other.m_map; }
 | |
|         bool operator==(EndIterator const&) const { return is_end(); }
 | |
| 
 | |
|     private:
 | |
|         friend class Map;
 | |
|         IteratorImpl(Map const& map) requires(IsConst)
 | |
|             : m_map(map)
 | |
|         {
 | |
|             ensure_index();
 | |
|         }
 | |
| 
 | |
|         IteratorImpl(Map& map) requires(!IsConst)
 | |
|             : m_map(map)
 | |
|         {
 | |
|             ensure_index();
 | |
|         }
 | |
| 
 | |
|         void ensure_index() const
 | |
|         {
 | |
|             if (m_map.m_keys.is_empty())
 | |
|                 m_index = m_map.m_next_insertion_id;
 | |
|             else
 | |
|                 m_index = m_map.m_keys.begin().key();
 | |
|         }
 | |
| 
 | |
|         void ensure_next_element() const
 | |
|         {
 | |
|             if (auto it = m_map.m_keys.find_smallest_not_below_iterator(m_index); it.is_end())
 | |
|                 m_index = m_map.m_next_insertion_id;
 | |
|             else
 | |
|                 m_index = it.key();
 | |
|         }
 | |
| 
 | |
|         Conditional<IsConst, Map const&, Map&> m_map;
 | |
|         mutable size_t m_index { 0 };
 | |
|     };
 | |
| 
 | |
|     using Iterator = IteratorImpl<false>;
 | |
|     using ConstIterator = IteratorImpl<true>;
 | |
| 
 | |
|     ConstIterator begin() const { return { *this }; }
 | |
|     Iterator begin() { return { *this }; }
 | |
|     EndIterator end() const { return {}; }
 | |
| 
 | |
| private:
 | |
|     explicit Map(Object& prototype);
 | |
|     virtual void visit_edges(Visitor& visitor) override;
 | |
| 
 | |
|     size_t m_next_insertion_id { 0 };
 | |
|     RedBlackTree<size_t, Value> m_keys;
 | |
|     HashMap<Value, Value, ValueTraits> m_entries;
 | |
| };
 | |
| 
 | |
| }
 |