gfx/graphite2/src/inc/Sparse.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* GRAPHITE2 LICENSING
michael@0 2
michael@0 3 Copyright 2011, SIL International
michael@0 4 All rights reserved.
michael@0 5
michael@0 6 This library is free software; you can redistribute it and/or modify
michael@0 7 it under the terms of the GNU Lesser General Public License as published
michael@0 8 by the Free Software Foundation; either version 2.1 of License, or
michael@0 9 (at your option) any later version.
michael@0 10
michael@0 11 This program is distributed in the hope that it will be useful,
michael@0 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
michael@0 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
michael@0 14 Lesser General Public License for more details.
michael@0 15
michael@0 16 You should also have received a copy of the GNU Lesser General Public
michael@0 17 License along with this library in the file named "LICENSE".
michael@0 18 If not, write to the Free Software Foundation, 51 Franklin Street,
michael@0 19 Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
michael@0 20 internet at http://www.fsf.org/licenses/lgpl.html.
michael@0 21
michael@0 22 Alternatively, the contents of this file may be used under the terms of the
michael@0 23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
michael@0 24 License, as published by the Free Software Foundation, either version 2
michael@0 25 of the License or (at your option) any later version.
michael@0 26 */
michael@0 27 #pragma once
michael@0 28 #include <iterator>
michael@0 29 #include <utility>
michael@0 30
michael@0 31 #include "inc/Main.h"
michael@0 32
michael@0 33 namespace graphite2 {
michael@0 34
michael@0 35
michael@0 36 // A read-only packed fast sparse array of uint16 with uint16 keys.
michael@0 37 // Like most container classes this has capacity and size properties and these
michael@0 38 // refer to the number of stored entries and the number of addressable entries
michael@0 39 // as normal. However due the sparse nature the capacity is always <= than the
michael@0 40 // size.
michael@0 41 class sparse
michael@0 42 {
michael@0 43 public:
michael@0 44 typedef uint16 key_type;
michael@0 45 typedef uint16 mapped_type;
michael@0 46 typedef std::pair<const key_type, mapped_type> value_type;
michael@0 47
michael@0 48 private:
michael@0 49 typedef unsigned long mask_t;
michael@0 50
michael@0 51 static const unsigned char SIZEOF_CHUNK = (sizeof(mask_t) - sizeof(key_type))*8;
michael@0 52
michael@0 53 struct chunk
michael@0 54 {
michael@0 55 mask_t mask:SIZEOF_CHUNK;
michael@0 56 key_type offset;
michael@0 57 };
michael@0 58
michael@0 59 static chunk empty_chunk;
michael@0 60 sparse(const sparse &);
michael@0 61 sparse & operator = (const sparse &);
michael@0 62
michael@0 63 public:
michael@0 64 template<typename I>
michael@0 65 sparse(I first, const I last);
michael@0 66 sparse() throw();
michael@0 67 ~sparse() throw();
michael@0 68
michael@0 69 operator bool () const throw();
michael@0 70 mapped_type operator [] (const key_type k) const throw();
michael@0 71
michael@0 72 size_t capacity() const throw();
michael@0 73 size_t size() const throw();
michael@0 74
michael@0 75 size_t _sizeof() const throw();
michael@0 76
michael@0 77 CLASS_NEW_DELETE;
michael@0 78
michael@0 79 private:
michael@0 80 union {
michael@0 81 chunk * map;
michael@0 82 mapped_type * values;
michael@0 83 } m_array;
michael@0 84 key_type m_nchunks;
michael@0 85 };
michael@0 86
michael@0 87
michael@0 88 inline
michael@0 89 sparse::sparse() throw() : m_nchunks(0)
michael@0 90 {
michael@0 91 m_array.map = &empty_chunk;
michael@0 92 }
michael@0 93
michael@0 94
michael@0 95 template <typename I>
michael@0 96 sparse::sparse(I attr, const I last)
michael@0 97 : m_nchunks(0)
michael@0 98 {
michael@0 99 m_array.map = 0;
michael@0 100
michael@0 101 // Find the maximum extent of the key space.
michael@0 102 size_t n_values=0;
michael@0 103 long lastkey = -1;
michael@0 104 for (I i = attr; i != last; ++i, ++n_values)
michael@0 105 {
michael@0 106 const typename std::iterator_traits<I>::value_type v = *i;
michael@0 107 if (v.second == 0) { --n_values; continue; }
michael@0 108 if (v.first <= lastkey) { m_nchunks = 0; return; }
michael@0 109
michael@0 110 lastkey = v.first;
michael@0 111 const key_type k = v.first / SIZEOF_CHUNK;
michael@0 112 if (k >= m_nchunks) m_nchunks = k+1;
michael@0 113 }
michael@0 114 if (m_nchunks == 0)
michael@0 115 {
michael@0 116 m_array.map=&empty_chunk;
michael@0 117 return;
michael@0 118 }
michael@0 119
michael@0 120 m_array.values = grzeroalloc<mapped_type>((m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)
michael@0 121 / sizeof(mapped_type)
michael@0 122 + n_values);
michael@0 123
michael@0 124 if (m_array.values == 0)
michael@0 125 {
michael@0 126 free(m_array.values); m_array.map=0;
michael@0 127 return;
michael@0 128 }
michael@0 129
michael@0 130 chunk * ci = m_array.map;
michael@0 131 ci->offset = (m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)/sizeof(mapped_type);
michael@0 132 mapped_type * vi = m_array.values + ci->offset;
michael@0 133 for (; attr != last; ++attr, ++vi)
michael@0 134 {
michael@0 135 const typename std::iterator_traits<I>::value_type v = *attr;
michael@0 136 if (v.second == 0) { --vi; continue; }
michael@0 137
michael@0 138 chunk * const ci_ = m_array.map + v.first/SIZEOF_CHUNK;
michael@0 139
michael@0 140 if (ci != ci_)
michael@0 141 {
michael@0 142 ci = ci_;
michael@0 143 ci->offset = vi - m_array.values;
michael@0 144 }
michael@0 145
michael@0 146 ci->mask |= 1UL << (SIZEOF_CHUNK - 1 - (v.first % SIZEOF_CHUNK));
michael@0 147 *vi = v.second;
michael@0 148 }
michael@0 149 }
michael@0 150
michael@0 151
michael@0 152 inline
michael@0 153 sparse::operator bool () const throw()
michael@0 154 {
michael@0 155 return m_array.map != 0;
michael@0 156 }
michael@0 157
michael@0 158 inline
michael@0 159 size_t sparse::size() const throw()
michael@0 160 {
michael@0 161 return m_nchunks*SIZEOF_CHUNK;
michael@0 162 }
michael@0 163
michael@0 164 inline
michael@0 165 size_t sparse::_sizeof() const throw()
michael@0 166 {
michael@0 167 return sizeof(sparse) + capacity()*sizeof(mapped_type) + m_nchunks*sizeof(chunk);
michael@0 168 }
michael@0 169
michael@0 170 } // namespace graphite2

mercurial