Path: blob/master/thirdparty/graphite/src/inc/Sparse.h
9906 views
// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later1// Copyright 2011, SIL International, All rights reserved.23#pragma once4#include <iterator>5#include <utility>67#include "inc/Main.h"89namespace graphite2 {101112// A read-only packed fast sparse array of uint16 with uint16 keys.13// Like most container classes this has capacity and size properties and these14// refer to the number of stored entries and the number of addressable entries15// as normal. However due the sparse nature the capacity is always <= than the16// size.17class sparse18{19public:20typedef uint16 key_type;21typedef uint16 mapped_type;22typedef std::pair<const key_type, mapped_type> value_type;2324private:25typedef unsigned long mask_t;2627static const unsigned char SIZEOF_CHUNK = (sizeof(mask_t) - sizeof(key_type))*8;2829struct chunk30{31mask_t mask:SIZEOF_CHUNK;32key_type offset;33};3435static const chunk empty_chunk;36sparse(const sparse &);37sparse & operator = (const sparse &);3839public:40template<typename I>41sparse(I first, const I last);42sparse() throw();43~sparse() throw();4445operator bool () const throw();46mapped_type operator [] (const key_type k) const throw();4748size_t capacity() const throw();49size_t size() const throw();5051size_t _sizeof() const throw();5253CLASS_NEW_DELETE;5455private:56union {57chunk * map;58mapped_type * values;59} m_array;60key_type m_nchunks;61};626364inline65sparse::sparse() throw() : m_nchunks(0)66{67m_array.map = const_cast<graphite2::sparse::chunk *>(&empty_chunk);68}697071template <typename I>72sparse::sparse(I attr, const I last)73: m_nchunks(0)74{75m_array.map = 0;7677// Find the maximum extent of the key space.78size_t n_values=0;79long lastkey = -1;80for (I i = attr; i != last; ++i, ++n_values)81{82const typename std::iterator_traits<I>::value_type v = *i;83if (v.second == 0) { --n_values; continue; }84if (v.first <= lastkey) { m_nchunks = 0; return; }8586lastkey = v.first;87const key_type k = v.first / SIZEOF_CHUNK;88if (k >= m_nchunks) m_nchunks = k+1;89}90if (m_nchunks == 0)91{92m_array.map=const_cast<graphite2::sparse::chunk *>(&empty_chunk);93return;94}9596m_array.values = grzeroalloc<mapped_type>((m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)97/ sizeof(mapped_type)98+ n_values);99100if (m_array.values == 0)101return;102103// coverity[forward_null : FALSE] Since m_array is union and m_array.values is not NULL104chunk * ci = m_array.map;105ci->offset = (m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)/sizeof(mapped_type);106mapped_type * vi = m_array.values + ci->offset;107for (; attr != last; ++attr, ++vi)108{109const typename std::iterator_traits<I>::value_type v = *attr;110if (v.second == 0) { --vi; continue; }111112chunk * const ci_ = m_array.map + v.first/SIZEOF_CHUNK;113114if (ci != ci_)115{116ci = ci_;117ci->offset = key_type(vi - m_array.values);118}119120ci->mask |= 1UL << (SIZEOF_CHUNK - 1 - (v.first % SIZEOF_CHUNK));121*vi = v.second;122}123}124125126inline127sparse::operator bool () const throw()128{129return m_array.map != 0;130}131132inline133size_t sparse::size() const throw()134{135return m_nchunks*SIZEOF_CHUNK;136}137138inline139size_t sparse::_sizeof() const throw()140{141return sizeof(sparse) + capacity()*sizeof(mapped_type) + m_nchunks*sizeof(chunk);142}143144} // namespace graphite2145146147