+ if (!first_change_only) {
+ const bool end_sample = get_unpacked_sample(end) & sig_mask;
+ if (last_sample != end_sample)
+ edges.emplace_back(end, end_sample);
+ edges.emplace_back(end + 1, end_sample);
+ }
+}
+
+void LogicSegment::get_surrounding_edges(vector<EdgePair> &dest,
+ uint64_t origin_sample, float min_length, int sig_index)
+{
+ if (origin_sample >= sample_count_)
+ return;
+
+ // Put the edges vector on the heap, it can become quite big until we can
+ // use a get_subsampled_edges() implementation that searches backwards
+ vector<EdgePair>* edges = new vector<EdgePair>;
+
+ // Get all edges to the left of origin_sample
+ get_subsampled_edges(*edges, 0, origin_sample, min_length, sig_index, false);
+
+ // If we don't specify "first only", the first and last edge are the states
+ // at samples 0 and origin_sample. If only those exist, there are no edges
+ if (edges->size() == 2) {
+ delete edges;
+ return;
+ }
+
+ // Dismiss the entry for origin_sample so that back() gives us the
+ // real last entry
+ edges->pop_back();
+ dest.push_back(edges->back());
+ edges->clear();
+
+ // Get first edge to the right of origin_sample
+ get_subsampled_edges(*edges, origin_sample, sample_count_, min_length, sig_index, true);
+
+ // "first only" is specified, so nothing needs to be dismissed
+ if (edges->size() == 0) {
+ delete edges;
+ return;
+ }
+
+ dest.push_back(edges->front());
+
+ delete edges;
+}
+
+void LogicSegment::reallocate_mipmap_level(MipMapLevel &m)
+{
+ lock_guard<recursive_mutex> lock(mutex_);
+
+ const uint64_t new_data_length = ((m.length + MipMapDataUnit - 1) /
+ MipMapDataUnit) * MipMapDataUnit;
+
+ if (new_data_length > m.data_length) {
+ m.data_length = new_data_length;
+
+ // Padding is added to allow for the uint64_t write word
+ m.data = realloc(m.data, new_data_length * unit_size_ +
+ sizeof(uint64_t));
+ }
+}
+
+void LogicSegment::append_payload_to_mipmap()
+{
+ MipMapLevel &m0 = mip_map_[0];
+ uint64_t prev_length;
+ uint8_t *dest_ptr;
+ SegmentDataIterator* it;
+ uint64_t accumulator;
+ unsigned int diff_counter;
+
+ // Expand the data buffer to fit the new samples
+ prev_length = m0.length;
+ m0.length = sample_count_ / MipMapScaleFactor;
+
+ // Break off if there are no new samples to compute
+ if (m0.length == prev_length)
+ return;
+
+ reallocate_mipmap_level(m0);
+
+ dest_ptr = (uint8_t*)m0.data + prev_length * unit_size_;
+
+ // Iterate through the samples to populate the first level mipmap
+ const uint64_t start_sample = prev_length * MipMapScaleFactor;
+ const uint64_t end_sample = m0.length * MipMapScaleFactor;
+
+ it = begin_sample_iteration(start_sample);
+ for (uint64_t i = start_sample; i < end_sample;) {
+ // Accumulate transitions which have occurred in this sample
+ accumulator = 0;
+ diff_counter = MipMapScaleFactor;
+ while (diff_counter-- > 0) {
+ const uint64_t sample = unpack_sample(get_iterator_value(it));
+ accumulator |= last_append_sample_ ^ sample;
+ last_append_sample_ = sample;
+ continue_sample_iteration(it, 1);
+ i++;
+ }
+
+ pack_sample(dest_ptr, accumulator);
+ dest_ptr += unit_size_;
+ }
+ end_sample_iteration(it);
+
+ // Compute higher level mipmaps
+ for (unsigned int level = 1; level < ScaleStepCount; level++) {
+ MipMapLevel &m = mip_map_[level];
+ const MipMapLevel &ml = mip_map_[level - 1];
+
+ // Expand the data buffer to fit the new samples
+ prev_length = m.length;
+ m.length = ml.length / MipMapScaleFactor;
+
+ // Break off if there are no more samples to be computed
+ if (m.length == prev_length)
+ break;
+
+ reallocate_mipmap_level(m);
+
+ // Subsample the lower level
+ const uint8_t* src_ptr = (uint8_t*)ml.data +
+ unit_size_ * prev_length * MipMapScaleFactor;
+ const uint8_t *const end_dest_ptr =
+ (uint8_t*)m.data + unit_size_ * m.length;
+
+ for (dest_ptr = (uint8_t*)m.data +
+ unit_size_ * prev_length;
+ dest_ptr < end_dest_ptr;
+ dest_ptr += unit_size_) {
+ accumulator = 0;
+ diff_counter = MipMapScaleFactor;
+ while (diff_counter-- > 0) {
+ accumulator |= unpack_sample(src_ptr);
+ src_ptr += unit_size_;
+ }
+
+ pack_sample(dest_ptr, accumulator);
+ }
+ }
+}
+
+uint64_t LogicSegment::get_unpacked_sample(uint64_t index) const
+{
+ assert(index < sample_count_);
+
+ assert(unit_size_ <= 8); // 8 * 8 = 64 channels
+ uint8_t data[8];
+
+ get_raw_samples(index, 1, data);
+
+ return unpack_sample(data);