git-subtree-dir: third_party/libosmium git-subtree-split: 2282c8450bae55839372a2002db7ca754530d2fc
		
			
				
	
	
		
			266 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef OSMIUM_IO_DETAIL_STRING_TABLE_HPP
 | |
| #define OSMIUM_IO_DETAIL_STRING_TABLE_HPP
 | |
| 
 | |
| /*
 | |
| 
 | |
| This file is part of Osmium (http://osmcode.org/libosmium).
 | |
| 
 | |
| Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
 | |
| 
 | |
| Boost Software License - Version 1.0 - August 17th, 2003
 | |
| 
 | |
| Permission is hereby granted, free of charge, to any person or organization
 | |
| obtaining a copy of the software and accompanying documentation covered by
 | |
| this license (the "Software") to use, reproduce, display, distribute,
 | |
| execute, and transmit the Software, and to prepare derivative works of the
 | |
| Software, and to permit third-parties to whom the Software is furnished to
 | |
| do so, all subject to the following:
 | |
| 
 | |
| The copyright notices in the Software and this entire statement, including
 | |
| the above license grant, this restriction and the following disclaimer,
 | |
| must be included in all copies of the Software, in whole or in part, and
 | |
| all derivative works of the Software, unless such copies or derivative
 | |
| works are solely in the form of machine-executable object code generated by
 | |
| a source language processor.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 | |
| SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 | |
| FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 | |
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | |
| DEALINGS IN THE SOFTWARE.
 | |
| 
 | |
| */
 | |
| 
 | |
| #include <cassert>
 | |
| #include <cstdint>
 | |
| #include <cstdlib>
 | |
| #include <cstring>
 | |
| #include <iterator>
 | |
| #include <list>
 | |
| #include <map>
 | |
| #include <string>
 | |
| 
 | |
| #include <osmium/io/detail/pbf.hpp>
 | |
| 
 | |
| namespace osmium {
 | |
| 
 | |
|     namespace io {
 | |
| 
 | |
|         namespace detail {
 | |
| 
 | |
|             /**
 | |
|              * class StringStore
 | |
|              *
 | |
|              * Storage of lots of strings (const char *). Memory is allocated in chunks.
 | |
|              * If a string is added and there is no space in the current chunk, a new
 | |
|              * chunk will be allocated. Strings added to the store must not be larger
 | |
|              * than the chunk size.
 | |
|              *
 | |
|              * All memory is released when the destructor is called. There is no other way
 | |
|              * to release all or part of the memory.
 | |
|              *
 | |
|              */
 | |
|             class StringStore {
 | |
| 
 | |
|                 size_t m_chunk_size;
 | |
| 
 | |
|                 std::list<std::string> m_chunks;
 | |
| 
 | |
|                 void add_chunk() {
 | |
|                     m_chunks.push_front(std::string());
 | |
|                     m_chunks.front().reserve(m_chunk_size);
 | |
|                 }
 | |
| 
 | |
|             public:
 | |
| 
 | |
|                 explicit StringStore(size_t chunk_size) :
 | |
|                     m_chunk_size(chunk_size),
 | |
|                     m_chunks() {
 | |
|                     add_chunk();
 | |
|                 }
 | |
| 
 | |
|                 void clear() noexcept {
 | |
|                     m_chunks.erase(std::next(m_chunks.begin()), m_chunks.end());
 | |
|                     m_chunks.front().clear();
 | |
|                 }
 | |
| 
 | |
|                 /**
 | |
|                  * Add a null terminated string to the store. This will
 | |
|                  * automatically get more memory if we are out.
 | |
|                  * Returns a pointer to the copy of the string we have
 | |
|                  * allocated.
 | |
|                  */
 | |
|                 const char* add(const char* string) {
 | |
|                     size_t len = std::strlen(string) + 1;
 | |
| 
 | |
|                     assert(len <= m_chunk_size);
 | |
| 
 | |
|                     size_t chunk_len = m_chunks.front().size();
 | |
|                     if (chunk_len + len > m_chunks.front().capacity()) {
 | |
|                         add_chunk();
 | |
|                         chunk_len = 0;
 | |
|                     }
 | |
| 
 | |
|                     m_chunks.front().append(string);
 | |
|                     m_chunks.front().append(1, '\0');
 | |
| 
 | |
|                     return m_chunks.front().c_str() + chunk_len;
 | |
|                 }
 | |
| 
 | |
|                 class const_iterator : public std::iterator<std::forward_iterator_tag, const char*> {
 | |
| 
 | |
|                     typedef std::list<std::string>::const_iterator it_type;
 | |
|                     it_type m_it;
 | |
|                     const it_type m_last;
 | |
|                     const char* m_pos;
 | |
| 
 | |
|                 public:
 | |
| 
 | |
|                     const_iterator(it_type it, it_type last) :
 | |
|                         m_it(it),
 | |
|                         m_last(last),
 | |
|                         m_pos(it == last ? nullptr : m_it->c_str()) {
 | |
|                     }
 | |
| 
 | |
|                     const_iterator& operator++() {
 | |
|                         assert(m_it != m_last);
 | |
|                         auto last_pos = m_it->c_str() + m_it->size();
 | |
|                         while (m_pos != last_pos && *m_pos) ++m_pos;
 | |
|                         if (m_pos != last_pos) ++m_pos;
 | |
|                         if (m_pos == last_pos) {
 | |
|                             ++m_it;
 | |
|                             if (m_it != m_last) {
 | |
|                                 m_pos = m_it->c_str();
 | |
|                             } else {
 | |
|                                 m_pos = nullptr;
 | |
|                             }
 | |
|                         }
 | |
|                         return *this;
 | |
|                     }
 | |
| 
 | |
|                     const_iterator operator++(int) {
 | |
|                         const_iterator tmp(*this);
 | |
|                         operator++();
 | |
|                         return tmp;
 | |
|                     }
 | |
| 
 | |
|                     bool operator==(const const_iterator& rhs) const {
 | |
|                         return m_it == rhs.m_it && m_pos == rhs.m_pos;
 | |
|                     }
 | |
| 
 | |
|                     bool operator!=(const const_iterator& rhs) const {
 | |
|                         return !(*this == rhs);
 | |
|                     }
 | |
| 
 | |
|                     const char* operator*() const {
 | |
|                         assert(m_it != m_last);
 | |
|                         assert(m_pos != nullptr);
 | |
|                         return m_pos;
 | |
|                     }
 | |
| 
 | |
|                 }; // class const_iterator
 | |
| 
 | |
|                 const_iterator begin() const {
 | |
|                     if (m_chunks.front().empty()) {
 | |
|                         return end();
 | |
|                     }
 | |
|                     return const_iterator(m_chunks.begin(), m_chunks.end());
 | |
|                 }
 | |
| 
 | |
|                 const_iterator end() const {
 | |
|                     return const_iterator(m_chunks.end(), m_chunks.end());
 | |
|                 }
 | |
| 
 | |
|                 // These functions get you some idea how much memory was
 | |
|                 // used.
 | |
|                 size_t get_chunk_size() const noexcept {
 | |
|                     return m_chunk_size;
 | |
|                 }
 | |
| 
 | |
|                 size_t get_chunk_count() const noexcept {
 | |
|                     return m_chunks.size();
 | |
|                 }
 | |
| 
 | |
|                 size_t get_used_bytes_in_last_chunk() const noexcept {
 | |
|                     return m_chunks.front().size();
 | |
|                 }
 | |
| 
 | |
|             }; // class StringStore
 | |
| 
 | |
|             struct StrComp {
 | |
| 
 | |
|                 bool operator()(const char* lhs, const char* rhs) const {
 | |
|                     return strcmp(lhs, rhs) < 0;
 | |
|                 }
 | |
| 
 | |
|             }; // struct StrComp
 | |
| 
 | |
|             class StringTable {
 | |
| 
 | |
|                 // This is the maximum number of entries in a string table.
 | |
|                 // This should never be reached in practice but we better
 | |
|                 // make sure it doesn't. If we had max_uncompressed_blob_size
 | |
|                 // many entries, we are sure they would never fit into a PBF
 | |
|                 // Blob.
 | |
|                 static constexpr const uint32_t max_entries = max_uncompressed_blob_size;
 | |
| 
 | |
|                 StringStore m_strings;
 | |
|                 std::map<const char*, size_t, StrComp> m_index;
 | |
|                 uint32_t m_size;
 | |
| 
 | |
|             public:
 | |
| 
 | |
|                 StringTable() :
 | |
|                     m_strings(1024 * 1024),
 | |
|                     m_index(),
 | |
|                     m_size(0) {
 | |
|                     m_strings.add("");
 | |
|                 }
 | |
| 
 | |
|                 void clear() {
 | |
|                     m_strings.clear();
 | |
|                     m_index.clear();
 | |
|                     m_size = 0;
 | |
|                     m_strings.add("");
 | |
|                 }
 | |
| 
 | |
|                 uint32_t size() const noexcept {
 | |
|                     return m_size + 1;
 | |
|                 }
 | |
| 
 | |
|                 uint32_t add(const char* s) {
 | |
|                     auto f = m_index.find(s);
 | |
|                     if (f != m_index.end()) {
 | |
|                         return uint32_t(f->second);
 | |
|                     }
 | |
| 
 | |
|                     const char* cs = m_strings.add(s);
 | |
|                     m_index[cs] = ++m_size;
 | |
| 
 | |
|                     if (m_size > max_entries) {
 | |
|                         throw osmium::pbf_error("string table has too many entries");
 | |
|                     }
 | |
| 
 | |
|                     return m_size;
 | |
|                 }
 | |
| 
 | |
|                 StringStore::const_iterator begin() const {
 | |
|                     return m_strings.begin();
 | |
|                 }
 | |
| 
 | |
|                 StringStore::const_iterator end() const {
 | |
|                     return m_strings.end();
 | |
|                 }
 | |
| 
 | |
|             }; // class StringTable
 | |
| 
 | |
|         } // namespace detail
 | |
| 
 | |
|     } // namespace io
 | |
| 
 | |
| } // namespace osmium
 | |
| 
 | |
| #endif // OSMIUM_IO_DETAIL_STRING_TABLE_HPP
 |