<commit_before>#include <iostream>
#include <string>
#include <iomanip>
#include <stack>
#include <limits>
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cassert>

#include "matrix.h"

#ifdef DEBUG
    #define LOG(x) std::cerr << x
#else
    #define LOG(x)
#endif

using namespace std;

// Largest neighborhood to explore during 2-opt.
const size_t TWOOPT_MAX_NEIGHBORS = 100;

// Output stream operator (convenient for printing tours).
ostream& operator<<(ostream& os, const vector<size_t>& v) {
    for (auto e : v)
        os << e << ' ';
    os << endl;
    return os;
}

/**
 * Create a distance matrix from an input stream and return it.
 *
 * @param in Input stream.
 * @return The read distance matrix.
 */
Matrix<uint32_t> createDistanceMatrix(istream& in) {
    // Read vertex coordinates.
    size_t N;
    in >> N;
    vector<double> x(N);
    vector<double> y(N);
    for (size_t i = 0; i < N; ++i) {
        in >> x[i] >> y[i];
    }

    // Calculate distance matrix.
    Matrix<uint32_t> d(N, N);
    for (size_t i = 0; i < N; ++i) {
        for (size_t j = i + 1; j < N; ++j) {
            d[i][j] = d[j][i] = round(sqrt(pow(x[i]-x[j], 2) + pow(y[i]-y[j], 2)));
        }
    }

    return d;
}

/**
 * Calculate minimum spanning tree using Prim's algorithm.
 *
 * @param d Distance matrix.
 * @return The minimum spanning tree.
 */
Matrix<uint32_t> primMST(const Matrix<uint32_t>& d) {
    size_t N = d.rows();

    vector<bool> inMST(N);
    vector<uint32_t> cost(N);
    vector<uint32_t> parent(N);
    fill(inMST.begin(), inMST.end(), false);
    fill(cost.begin(), cost.end(), numeric_limits<uint32_t>::max());
    cost[0] = 0;

    for (size_t added = 0; added < N - 1; ++added) {
        // Find lowest cost city not in MST and add it to MST.
        size_t u = 0;
        uint32_t c = numeric_limits<int>::max();
        for (size_t v = 0; v < N; ++v) {
            if (cost[v] < c && !inMST[v]) {
                u = v;
                c = cost[v];
            }
        }
        inMST[u] = true;

        // For each neighbor v of u not already in MST.
        for (size_t v = 0; v < N; ++v) {
            if (0 < d[u][v] && d[u][v] < cost[v] && !inMST[v]) {
                // d[u][v] is lower than current cost of v, so mark u
                // as parent of v and set cost of v to d[u][v].
                parent[v] = u;
                cost[v] = d[u][v];
            }
        }
    }

    // Build MST matrix.
    Matrix<uint32_t> MST(N, N);
    for (size_t v = 1; v < N; ++v) {
        MST[parent[v]][v] = d[parent[v]][v];
    }

    return MST;
}

/**
 * Calculates a 2-approximation TSP tour from a minimum spanning tree.
 *
 * @param MST Input minimum spanning tree.
 * @return 2-approximation TSP tour.
 */
vector<uint16_t> twoApprox(const Matrix<uint32_t>& MST) {
    size_t N = MST.rows();

    vector<uint16_t> tour;
    vector<bool> visited(N);
    stack<uint16_t> stack;
    stack.push(0);

    while (tour.size() < N) {
        size_t u = stack.top();
        stack.pop();
        if (!visited[u]) {
            tour.push_back(u);
            visited[u] = true;
            for (uint16_t v = 0; v < N; ++v) {
                if (MST[u][v] != 0) {
                    stack.push(v);
                }
            }
        }
    }

    return tour;
}

/**
 * Calculates a greedy TSP tour starting at city u.
 *
 * This is the naive algorithm given in the Kattis problem description.
 *
 * @param d Distance matrix.
 * @param u Start city of tour.
 * @return Greedy TSP tour.
 */
vector<uint16_t> greedy(const Matrix<uint32_t>& d, size_t u) {
    size_t N = d.rows();
    vector<uint16_t> tour(N);
    vector<bool> used(N, false);
    tour[0] = u;
    used[u] = true;
    for (size_t i = 1; i < N; ++i) {
        // Find k, the closest city to the (i - 1):th city in tour.
        int32_t k = -1;
        for (uint16_t j = 0; j < N; ++j) {
            if (!used[j] && (k == -1 || d[tour[i-1]][j] < d[tour[i-1]][k])) {
                k = j;
            }
        }
        tour[i] = k;
        used[k] = true;
    }
    return tour;
}

/**
 * Calculate K-nearest neighbors matrix from a distance matrix.
 *
 * @param d Distance matrix.
 * @return d.rows() x (d.cols - 1) matrix where element i,j is
 *         the j:th nearest neighbor of city i.
 */
Matrix<uint16_t> createNeighborsMatrix(const Matrix<uint32_t>& d, size_t K) {
    size_t N = d.rows();
    size_t M = d.cols() - 1;
    K = min(M, K);
    Matrix<uint16_t> neighbor(N, K);
    std::vector<uint16_t> row(M); // For sorting.

    for (size_t i = 0; i < N; ++i) {
        // Fill row with 0, 1, ..., i - 1, i + 1, ..., M - 1.
        uint16_t k = 0;
        for (size_t j = 0; j < M; ++j, ++k) {
            row[j] = (i == j) ? ++k : k;
        }
        // Sort K nearest row elements by distance to i.
        partial_sort(row.begin(), row.begin() + K, row.end(),
            [&](uint16_t j, uint16_t k) {
                return d[i][j] < d[i][k];
            }
        );
        // Copy first K elements (now sorted) to neighbor matrix.
        copy(row.begin(), row.begin() + K, neighbor[i]);
    }
    return neighbor;
}

/**
 * Reverse a segment of a tour.
 *
 * This functions reverses the segment [start, end] of the given
 * tour and updates the position vector accordingly.
 *
 * @param tour The input tour.
 * @param start Start index of segment to reverse.
 * @param end End index of segment to reverse.
 * @param position Vector containing positions of cities in the tour, will
 *                 be updated to reflect the reversal.
 */
void reverse(vector<uint16_t> &tour, size_t start, size_t end,
        vector<uint16_t>& position) {
    size_t N = tour.size();
    size_t numSwaps = (((start <= end ? end - start : (end + N) - start) + 1)/2);
    uint16_t i = start;
    uint16_t j = end;
    for (size_t n = 0; n < numSwaps; ++n) {
        swap(tour[i], tour[j]);
        position[tour[i]] = i;
        position[tour[j]] = j;
        i = (i + 1) % N;
        j = ((j + N) - 1) % N;
    }
}

/**
 * Returns the shortest distance d[i][j], i != j in the given distance matrix.
 *
 * @param d Distance matrix.
 * @return Minimum distance in d.
 */
uint32_t minDistance(const Matrix<uint32_t>& d) {
    size_t N = d.rows();
    uint32_t min = numeric_limits<size_t>::max();
    for (size_t i = 0; i < N; ++i) {
        for (size_t j = 0; j < N; ++j) {
            if (i != j)
                min = std::min(min, d[i][j]);
        }
    }
    return min;
}

/**
 * Returns the longest inter-city distance in the given tour.
 *
 * @param tour Input tour.
 * @param d Distance matrix.
 * @return Maximum inter-city distance in tour.
 */
uint32_t maxDistance(const vector<uint16_t>& tour, const Matrix<uint32_t>& d) {
    size_t N = tour.size();
    uint32_t max = 0;
    for (size_t i = 0, j = 1; i < N; ++i, ++j) {
        max = std::max(max, d[tour[i]][tour[j % N]]);
    }
    return max;
}

/**
 * Returns the total length of a tour.
 *
 * @param tour The input tour.
 * @param d Distance matrix.
 * @return The total length of the tour.
 */
uint64_t length(const vector<uint32_t>& tour, const Matrix<uint32_t>& d) {
    size_t N = tour.size();
    uint64_t length = 0;
    for (size_t i = 0, j = 1; i < N; ++i, ++j) {
        length += d[tour[i]][tour[j % N]];
    }
    return length;
}

/**
 * Perform a 2-opt pass on the given tour.
 *
 * This function uses the fast approach described on page 12 of "Large-Step
 * Markov Chains for the Traveling Salesman Problem" (Martin/Otto/Felten, 1991)
 *
 * @param tour The tour to optimize.
 * @param d Distance matrix.
 * @param neighbor Nearest neighbors matrix.
 * @param min Shortest possible inter-city distance.
 * @return true if the tour was improved, otherwise false.
 */
bool twoOpt(vector<uint16_t>& tour, const Matrix<uint32_t>& d,
        const Matrix<uint16_t>& neighbor, uint32_t min) {
    size_t N = d.rows();
    bool didImprove = false;

    // Initialize city tour position vector.
    vector<uint16_t> position(N);
    for (uint16_t i = 0; i < N; ++i) {
        position[tour[i]] = i; // tour[i] is the i:th city in tour.
    }

    uint16_t u, v, w, z;
    size_t u_i, v_i, w_i, z_i;
    uint32_t max = maxDistance(tour, d); // Longest link in current tour.

    for (u_i = 0, v_i = 1; u_i < N; ++u_i, ++v_i) {
        // For each edge (u, v).
        u = tour[u_i];
        v = tour[v_i % N];
        for (size_t k = 0; k < neighbor.cols(); ++k) {
            // Visit nearby edges (w, z).
            w_i = position[neighbor[u][k]];
            z_i = w_i + 1;
            w = tour[w_i]; // w is the k:th closest neighbor of u.
            z = tour[z_i % N];

            if (v == w || z == u) {
                continue; // Skip adjacent edges.
            }

            // d[u][w] + min is a lower bound on new length.
            // d[u][v] + max is an upper bound on old length.
            if (d[u][w] + min > d[u][v] + max) {
                break; // Go to next edge (u, v).
            }

            if (d[u][w] + d[v][z] < d[u][v] + d[w][z]) {
                //   --u w--        --u-w->
                //      X     ===>
                //   <-z v->        <-z-v--
                reverse(tour, v_i % N, w_i, position);

                // FIXME: Is this enough to update max?
                max = std::max(max, std::max(d[u][w], d[v][z]));

                didImprove = true;
                break;
            }
        }
    }

    return didImprove;
}

int main(int argc, char *argv[]) {
    // Create distance matrix from standard input.
    Matrix<uint32_t> d = createDistanceMatrix(cin);

    // Calculate 2-approximation tour from minimum spanning tree.
    //Matrix<uint32_t> MST = primMST(d);
    //vector<uint16_t> tour = twoApprox(MST);

    // Calculate a greedy tour.
    vector<uint16_t> tour = greedy(d, 0);

    // Calculate nearest neighbors and smallest possible city distance.
    Matrix<uint16_t> neighbor = createNeighborsMatrix(d, TWOOPT_MAX_NEIGHBORS);
    uint32_t min = minDistance(d);

    // Optimize tour using 2-opt.
    bool didImprove;
    do {
        didImprove = twoOpt(tour, d, neighbor, min);
    } while (didImprove);

    // Print tour.
    for (auto city : tour) {
        cout << city << endl;
    }

    return 0;
}

<commit_msg>Iterate greedy + 2-opt for 1950 ms (28.8 p on Kattis).<commit_after>#include <iostream>
#include <string>
#include <iomanip>
#include <stack>
#include <limits>
#include <algorithm>
#include <chrono>
#include <random>
#include <cmath>
#include <cstdint>
#include <cassert>

#include "matrix.h"

#ifdef DEBUG
    #define LOG(x) std::cerr << x
#else
    #define LOG(x)
#endif

using namespace std;

// Random number generator.
random_device rd;
default_random_engine rng(rd());

// Largest neighborhood to explore during 2-opt.
const size_t TWOOPT_MAX_NEIGHBORS = 100;

// Output stream operator (convenient for printing tours).
ostream& operator<<(ostream& os, const vector<size_t>& v) {
    for (auto e : v)
        os << e << ' ';
    os << endl;
    return os;
}

/**
 * Create a distance matrix from an input stream and return it.
 *
 * @param in Input stream.
 * @return The read distance matrix.
 */
Matrix<uint32_t> createDistanceMatrix(istream& in) {
    // Read vertex coordinates.
    size_t N;
    in >> N;
    vector<double> x(N);
    vector<double> y(N);
    for (size_t i = 0; i < N; ++i) {
        in >> x[i] >> y[i];
    }

    // Calculate distance matrix.
    Matrix<uint32_t> d(N, N);
    for (size_t i = 0; i < N; ++i) {
        for (size_t j = i + 1; j < N; ++j) {
            d[i][j] = d[j][i] = round(sqrt(pow(x[i]-x[j], 2) + pow(y[i]-y[j], 2)));
        }
    }

    return d;
}

/**
 * Calculate minimum spanning tree using Prim's algorithm.
 *
 * @param d Distance matrix.
 * @return The minimum spanning tree.
 */
Matrix<uint32_t> primMST(const Matrix<uint32_t>& d) {
    size_t N = d.rows();

    vector<bool> inMST(N);
    vector<uint32_t> cost(N);
    vector<uint32_t> parent(N);
    fill(inMST.begin(), inMST.end(), false);
    fill(cost.begin(), cost.end(), numeric_limits<uint32_t>::max());
    cost[0] = 0;

    for (size_t added = 0; added < N - 1; ++added) {
        // Find lowest cost city not in MST and add it to MST.
        size_t u = 0;
        uint32_t c = numeric_limits<int>::max();
        for (size_t v = 0; v < N; ++v) {
            if (cost[v] < c && !inMST[v]) {
                u = v;
                c = cost[v];
            }
        }
        inMST[u] = true;

        // For each neighbor v of u not already in MST.
        for (size_t v = 0; v < N; ++v) {
            if (0 < d[u][v] && d[u][v] < cost[v] && !inMST[v]) {
                // d[u][v] is lower than current cost of v, so mark u
                // as parent of v and set cost of v to d[u][v].
                parent[v] = u;
                cost[v] = d[u][v];
            }
        }
    }

    // Build MST matrix.
    Matrix<uint32_t> MST(N, N);
    for (size_t v = 1; v < N; ++v) {
        MST[parent[v]][v] = d[parent[v]][v];
    }

    return MST;
}

/**
 * Calculates a 2-approximation TSP tour from a minimum spanning tree.
 *
 * @param MST Input minimum spanning tree.
 * @return 2-approximation TSP tour.
 */
vector<uint16_t> twoApprox(const Matrix<uint32_t>& MST) {
    size_t N = MST.rows();

    vector<uint16_t> tour;
    vector<bool> visited(N);
    stack<uint16_t> stack;
    stack.push(0);

    while (tour.size() < N) {
        size_t u = stack.top();
        stack.pop();
        if (!visited[u]) {
            tour.push_back(u);
            visited[u] = true;
            for (uint16_t v = 0; v < N; ++v) {
                if (MST[u][v] != 0) {
                    stack.push(v);
                }
            }
        }
    }

    return tour;
}

/**
 * Calculates a greedy TSP tour starting at city u.
 *
 * This is the naive algorithm given in the Kattis problem description.
 *
 * @param d Distance matrix.
 * @param u Start city of tour.
 * @return Greedy TSP tour.
 */
vector<uint16_t> greedy(const Matrix<uint32_t>& d, size_t u) {
    size_t N = d.rows();
    vector<uint16_t> tour(N);
    vector<bool> used(N, false);
    tour[0] = u;
    used[u] = true;
    for (size_t i = 1; i < N; ++i) {
        // Find k, the closest city to the (i - 1):th city in tour.
        int32_t k = -1;
        for (uint16_t j = 0; j < N; ++j) {
            if (!used[j] && (k == -1 || d[tour[i-1]][j] < d[tour[i-1]][k])) {
                k = j;
            }
        }
        tour[i] = k;
        used[k] = true;
    }
    return tour;
}

/**
 * Calculate K-nearest neighbors matrix from a distance matrix.
 *
 * @param d Distance matrix.
 * @return d.rows() x (d.cols - 1) matrix where element i,j is
 *         the j:th nearest neighbor of city i.
 */
Matrix<uint16_t> createNeighborsMatrix(const Matrix<uint32_t>& d, size_t K) {
    size_t N = d.rows();
    size_t M = d.cols() - 1;
    K = min(M, K);
    Matrix<uint16_t> neighbor(N, K);
    std::vector<uint16_t> row(M); // For sorting.

    for (size_t i = 0; i < N; ++i) {
        // Fill row with 0, 1, ..., i - 1, i + 1, ..., M - 1.
        uint16_t k = 0;
        for (size_t j = 0; j < M; ++j, ++k) {
            row[j] = (i == j) ? ++k : k;
        }
        // Sort K nearest row elements by distance to i.
        partial_sort(row.begin(), row.begin() + K, row.end(),
            [&](uint16_t j, uint16_t k) {
                return d[i][j] < d[i][k];
            }
        );
        // Copy first K elements (now sorted) to neighbor matrix.
        copy(row.begin(), row.begin() + K, neighbor[i]);
    }
    return neighbor;
}

/**
 * Reverse a segment of a tour.
 *
 * This functions reverses the segment [start, end] of the given
 * tour and updates the position vector accordingly.
 *
 * @param tour The input tour.
 * @param start Start index of segment to reverse.
 * @param end End index of segment to reverse.
 * @param position Vector containing positions of cities in the tour, will
 *                 be updated to reflect the reversal.
 */
void reverse(vector<uint16_t> &tour, size_t start, size_t end,
        vector<uint16_t>& position) {
    size_t N = tour.size();
    size_t numSwaps = (((start <= end ? end - start : (end + N) - start) + 1)/2);
    uint16_t i = start;
    uint16_t j = end;
    for (size_t n = 0; n < numSwaps; ++n) {
        swap(tour[i], tour[j]);
        position[tour[i]] = i;
        position[tour[j]] = j;
        i = (i + 1) % N;
        j = ((j + N) - 1) % N;
    }
}

/**
 * Returns the shortest distance d[i][j], i != j in the given distance matrix.
 *
 * @param d Distance matrix.
 * @return Minimum distance in d.
 */
uint32_t minDistance(const Matrix<uint32_t>& d) {
    size_t N = d.rows();
    uint32_t min = numeric_limits<size_t>::max();
    for (size_t i = 0; i < N; ++i) {
        for (size_t j = 0; j < N; ++j) {
            if (i != j)
                min = std::min(min, d[i][j]);
        }
    }
    return min;
}

/**
 * Returns the longest inter-city distance in the given tour.
 *
 * @param tour Input tour.
 * @param d Distance matrix.
 * @return Maximum inter-city distance in tour.
 */
uint32_t maxDistance(const vector<uint16_t>& tour, const Matrix<uint32_t>& d) {
    size_t N = tour.size();
    uint32_t max = 0;
    for (size_t i = 0, j = 1; i < N; ++i, ++j) {
        max = std::max(max, d[tour[i]][tour[j % N]]);
    }
    return max;
}

/**
 * Returns the total length of a tour.
 *
 * @param tour The input tour.
 * @param d Distance matrix.
 * @return The total length of the tour.
 */
uint64_t length(const vector<uint16_t>& tour, const Matrix<uint32_t>& d) {
    size_t N = tour.size();
    uint64_t length = 0;
    for (size_t i = 0, j = 1; i < N; ++i, ++j) {
        length += d[tour[i]][tour[j % N]];
    }
    return length;
}

/**
 * Perform a 2-opt pass on the given tour.
 *
 * This function uses the fast approach described on page 12 of "Large-Step
 * Markov Chains for the Traveling Salesman Problem" (Martin/Otto/Felten, 1991)
 *
 * @param tour The tour to optimize.
 * @param d Distance matrix.
 * @param neighbor Nearest neighbors matrix.
 * @param min Shortest possible inter-city distance.
 * @return true if the tour was improved, otherwise false.
 */
bool twoOpt(vector<uint16_t>& tour, const Matrix<uint32_t>& d,
        const Matrix<uint16_t>& neighbor, uint32_t min) {
    size_t N = d.rows();
    bool didImprove = false;

    // Initialize city tour position vector.
    vector<uint16_t> position(N);
    for (uint16_t i = 0; i < N; ++i) {
        position[tour[i]] = i; // tour[i] is the i:th city in tour.
    }

    uint16_t u, v, w, z;
    size_t u_i, v_i, w_i, z_i;
    uint32_t max = maxDistance(tour, d); // Longest link in current tour.

    for (u_i = 0, v_i = 1; u_i < N; ++u_i, ++v_i) {
        // For each edge (u, v).
        u = tour[u_i];
        v = tour[v_i % N];
        for (size_t k = 0; k < neighbor.cols(); ++k) {
            // Visit nearby edges (w, z).
            w_i = position[neighbor[u][k]];
            z_i = w_i + 1;
            w = tour[w_i]; // w is the k:th closest neighbor of u.
            z = tour[z_i % N];

            if (v == w || z == u) {
                continue; // Skip adjacent edges.
            }

            // d[u][w] + min is a lower bound on new length.
            // d[u][v] + max is an upper bound on old length.
            if (d[u][w] + min > d[u][v] + max) {
                break; // Go to next edge (u, v).
            }

            if (d[u][w] + d[v][z] < d[u][v] + d[w][z]) {
                //   --u w--        --u-w->
                //      X     ===>
                //   <-z v->        <-z-v--
                reverse(tour, v_i % N, w_i, position);

                // FIXME: Is this enough to update max?
                max = std::max(max, std::max(d[u][w], d[v][z]));

                didImprove = true;
                break;
            }
        }
    }

    return didImprove;
}

int main(int argc, char *argv[]) {
    // Deadline is 1950 ms into the future.
    auto now = chrono::high_resolution_clock::now();
    auto deadline = now + chrono::duration<int, milli>(1950);

    // Create distance / nearest neighbors matrix.
    Matrix<uint32_t> d = createDistanceMatrix(cin);
    Matrix<uint16_t> neighbor = createNeighborsMatrix(d, TWOOPT_MAX_NEIGHBORS);

    uint32_t minCityDistance = minDistance(d); // Smallest city distance.

    // Create vector of random possible start cities.
    vector<uint16_t> startCities(d.rows());
    for (uint16_t i = 0; i < d.rows(); ++i) {
        startCities[i] = i;
    }
    shuffle(startCities.begin(), startCities.end(), rng);

    vector<vector<uint16_t> > tours;
    size_t minTour;
    uint64_t minLength = numeric_limits<uint64_t>::max();

    // For each possible start city.
    for (size_t i = 0; i < d.rows(); ++i) {
        // Create greedy tour starting in startCities[i].
        tours.emplace_back(d.rows());
        tours[i] = greedy(d, startCities[i]);

        // Optimize tour using 2-opt.
        bool didImprove;
        do {
            didImprove = twoOpt(tours[i], d, neighbor, minCityDistance);
        } while (didImprove);

        // Check if we got a shorter tour.
        uint64_t tourLength = length(tours[i], d);
        if (tourLength < minLength) {
            minTour = i;
            minLength = tourLength;
        }

        // Check if deadline has passed.
        if (chrono::high_resolution_clock::now() > deadline) {
            break;
        }
    }

    // Print the shortest tour.
    for (auto city : tours[minTour]) {
        cout << city << endl;
    }

    return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrTextureStripAtlas.h"
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrSurfaceContext.h"
#include "SkGr.h"
#include "SkPixelRef.h"
#include "SkTSearch.h"

#ifdef SK_DEBUG
    #define VALIDATE this->validate()
#else
    #define VALIDATE
#endif

class GrTextureStripAtlas::Hash : public SkTDynamicHash<GrTextureStripAtlas::AtlasEntry,
                                                        GrTextureStripAtlas::Desc> {};

int32_t GrTextureStripAtlas::gCacheCount = 0;

GrTextureStripAtlas::Hash* GrTextureStripAtlas::gAtlasCache = nullptr;

GrTextureStripAtlas::Hash* GrTextureStripAtlas::GetCache() {

    if (nullptr == gAtlasCache) {
        gAtlasCache = new Hash;
    }

    return gAtlasCache;
}

// Remove the specified atlas from the cache
void GrTextureStripAtlas::CleanUp(const GrContext*, void* info) {
    SkASSERT(info);

    AtlasEntry* entry = static_cast<AtlasEntry*>(info);

    // remove the cache entry
    GetCache()->remove(entry->fDesc);

    // remove the actual entry
    delete entry;

    if (0 == GetCache()->count()) {
        delete gAtlasCache;
        gAtlasCache = nullptr;
    }
}

GrTextureStripAtlas* GrTextureStripAtlas::GetAtlas(const GrTextureStripAtlas::Desc& desc) {
    AtlasEntry* entry = GetCache()->find(desc);
    if (nullptr == entry) {
        entry = new AtlasEntry;

        entry->fAtlas = new GrTextureStripAtlas(desc);
        entry->fDesc = desc;

        desc.fContext->addCleanUp(CleanUp, entry);

        GetCache()->add(entry);
    }

    return entry->fAtlas;
}

GrTextureStripAtlas::GrTextureStripAtlas(GrTextureStripAtlas::Desc desc)
    : fCacheKey(sk_atomic_inc(&gCacheCount))
    , fLockedRows(0)
    , fDesc(desc)
    , fNumRows(desc.fHeight / desc.fRowHeight)
    , fRows(new AtlasRow[fNumRows])
    , fLRUFront(nullptr)
    , fLRUBack(nullptr) {
    SkASSERT(fNumRows * fDesc.fRowHeight == fDesc.fHeight);
    this->initLRU();
    fNormalizedYHeight = SK_Scalar1 / fDesc.fHeight;
    VALIDATE;
}

GrTextureStripAtlas::~GrTextureStripAtlas() { delete[] fRows; }

int GrTextureStripAtlas::lockRow(const SkBitmap& bitmap) {
    VALIDATE;
    if (0 == fLockedRows) {
        this->lockTexture();
        if (!fTexContext) {
            return -1;
        }
    }

    int key = bitmap.getGenerationID();
    int rowNumber = -1;
    int index = this->searchByKey(key);

    if (index >= 0) {
        // We already have the data in a row, so we can just return that row
        AtlasRow* row = fKeyTable[index];
        if (0 == row->fLocks) {
            this->removeFromLRU(row);
        }
        ++row->fLocks;
        ++fLockedRows;

        // Since all the rows are always stored in a contiguous array, we can save the memory
        // required for storing row numbers and just compute it with some pointer arithmetic
        rowNumber = static_cast<int>(row - fRows);
    } else {
        // ~index is the index where we will insert the new key to keep things sorted
        index = ~index;

        // We don't have this data cached, so pick the least recently used row to copy into
        AtlasRow* row = this->getLRU();

        ++fLockedRows;

        if (nullptr == row) {
            // force a flush, which should unlock all the rows; then try again
            fDesc.fContext->flush();
            row = this->getLRU();
            if (nullptr == row) {
                --fLockedRows;
                return -1;
            }
        }

        this->removeFromLRU(row);

        uint32_t oldKey = row->fKey;

        // If we are writing into a row that already held bitmap data, we need to remove the
        // reference to that genID which is stored in our sorted table of key values.
        if (oldKey != kEmptyAtlasRowKey) {

            // Find the entry in the list; if it's before the index where we plan on adding the new
            // entry, we decrement since it will shift elements ahead of it back by one.
            int oldIndex = this->searchByKey(oldKey);
            if (oldIndex < index) {
                --index;
            }

            fKeyTable.remove(oldIndex);
        }

        row->fKey = key;
        row->fLocks = 1;
        fKeyTable.insert(index, 1, &row);
        rowNumber = static_cast<int>(row - fRows);

        SkAutoLockPixels lock(bitmap);

        SkASSERT(bitmap.width() == fDesc.fWidth);
        SkASSERT(bitmap.height() == fDesc.fRowHeight);

        // Pass in the kDontFlush flag, since we know we're writing to a part of this texture
        // that is not currently in use
        fTexContext->writePixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(),
                                 0, rowNumber * fDesc.fRowHeight,
                                 GrContext::kDontFlush_PixelOpsFlag);
    }

    SkASSERT(rowNumber >= 0);
    VALIDATE;
    return rowNumber;
}

sk_sp<GrTextureProxy> GrTextureStripAtlas::asTextureProxyRef() const {
    return fTexContext->asTextureProxyRef();
}

void GrTextureStripAtlas::unlockRow(int row) {
    VALIDATE;
    --fRows[row].fLocks;
    --fLockedRows;
    SkASSERT(fRows[row].fLocks >= 0 && fLockedRows >= 0);
    if (0 == fRows[row].fLocks) {
        this->appendLRU(fRows + row);
    }
    if (0 == fLockedRows) {
        this->unlockTexture();
    }
    VALIDATE;
}

GrTextureStripAtlas::AtlasRow* GrTextureStripAtlas::getLRU() {
    // Front is least-recently-used
    AtlasRow* row = fLRUFront;
    return row;
}

void GrTextureStripAtlas::lockTexture() {
    GrSurfaceDesc texDesc;
    texDesc.fWidth = fDesc.fWidth;
    texDesc.fHeight = fDesc.fHeight;
    texDesc.fConfig = fDesc.fConfig;
    texDesc.fIsMipMapped = false;

    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
    GrUniqueKey key;
    GrUniqueKey::Builder builder(&key, kDomain, 1);
    builder[0] = static_cast<uint32_t>(fCacheKey);
    builder.finish();

    // MDB TODO (caching): this side-steps the issue of proxies with unique IDs
    GrTexture* texture = fDesc.fContext->textureProvider()->findAndRefTextureByUniqueKey(key);
    if (!texture) {
        texture = fDesc.fContext->textureProvider()->createTexture(texDesc, SkBudgeted::kYes,
                                                                   nullptr, 0);
        if (!texture) {
            return;
        }

        // We will be issuing writes to the surface using kDontFlush_PixelOpsFlag, so we
        // need to make sure any existing IO is flushed
        fDesc.fContext->flushSurfaceIO(texture);
        fDesc.fContext->textureProvider()->assignUniqueKeyToTexture(key, texture);
        // This is a new texture, so all of our cache info is now invalid
        this->initLRU();
        fKeyTable.rewind();
    }
    SkASSERT(texture);
    fTexContext = fDesc.fContext->contextPriv().makeWrappedSurfaceContext(sk_ref_sp(texture));
}

void GrTextureStripAtlas::unlockTexture() {
    SkASSERT(fTexContext && 0 == fLockedRows);
    fTexContext.reset();
}

void GrTextureStripAtlas::initLRU() {
    fLRUFront = nullptr;
    fLRUBack = nullptr;
    // Initially all the rows are in the LRU list
    for (int i = 0; i < fNumRows; ++i) {
        fRows[i].fKey = kEmptyAtlasRowKey;
        fRows[i].fNext = nullptr;
        fRows[i].fPrev = nullptr;
        this->appendLRU(fRows + i);
    }
    SkASSERT(nullptr == fLRUFront || nullptr == fLRUFront->fPrev);
    SkASSERT(nullptr == fLRUBack || nullptr == fLRUBack->fNext);
}

void GrTextureStripAtlas::appendLRU(AtlasRow* row) {
    SkASSERT(nullptr == row->fPrev && nullptr == row->fNext);
    if (nullptr == fLRUFront && nullptr == fLRUBack) {
        fLRUFront = row;
        fLRUBack = row;
    } else {
        row->fPrev = fLRUBack;
        fLRUBack->fNext = row;
        fLRUBack = row;
    }
}

void GrTextureStripAtlas::removeFromLRU(AtlasRow* row) {
    SkASSERT(row);
    if (row->fNext && row->fPrev) {
        row->fPrev->fNext = row->fNext;
        row->fNext->fPrev = row->fPrev;
    } else {
        if (nullptr == row->fNext) {
            SkASSERT(row == fLRUBack);
            fLRUBack = row->fPrev;
            if (fLRUBack) {
                fLRUBack->fNext = nullptr;
            }
        }
        if (nullptr == row->fPrev) {
            SkASSERT(row == fLRUFront);
            fLRUFront = row->fNext;
            if (fLRUFront) {
                fLRUFront->fPrev = nullptr;
            }
        }
    }
    row->fNext = nullptr;
    row->fPrev = nullptr;
}

int GrTextureStripAtlas::searchByKey(uint32_t key) {
    AtlasRow target;
    target.fKey = key;
    return SkTSearch<const AtlasRow,
                     GrTextureStripAtlas::KeyLess>((const AtlasRow**)fKeyTable.begin(),
                                                   fKeyTable.count(),
                                                   &target,
                                                   sizeof(AtlasRow*));
}

#ifdef SK_DEBUG
void GrTextureStripAtlas::validate() {

    // Our key table should be sorted
    uint32_t prev = 1 > fKeyTable.count() ? 0 : fKeyTable[0]->fKey;
    for (int i = 1; i < fKeyTable.count(); ++i) {
        SkASSERT(prev < fKeyTable[i]->fKey);
        SkASSERT(fKeyTable[i]->fKey != kEmptyAtlasRowKey);
        prev = fKeyTable[i]->fKey;
    }

    int lruCount = 0;
    // Validate LRU pointers, and count LRU entries
    SkASSERT(nullptr == fLRUFront || nullptr == fLRUFront->fPrev);
    SkASSERT(nullptr == fLRUBack  || nullptr == fLRUBack->fNext);
    for (AtlasRow* r = fLRUFront; r != nullptr; r = r->fNext) {
        if (nullptr == r->fNext) {
            SkASSERT(r == fLRUBack);
        } else {
            SkASSERT(r->fNext->fPrev == r);
        }
        ++lruCount;
    }

    int rowLocks = 0;
    int freeRows = 0;

    for (int i = 0; i < fNumRows; ++i) {
        rowLocks += fRows[i].fLocks;
        if (0 == fRows[i].fLocks) {
            ++freeRows;
            bool inLRU = false;
            // Step through the LRU and make sure it's present
            for (AtlasRow* r = fLRUFront; r != nullptr; r = r->fNext) {
                if (r == &fRows[i]) {
                    inLRU = true;
                    break;
                }
            }
            SkASSERT(inLRU);
        } else {
            // If we are locked, we should have a key
            SkASSERT(kEmptyAtlasRowKey != fRows[i].fKey);
        }

        // If we have a key != kEmptyAtlasRowKey, it should be in the key table
        SkASSERT(fRows[i].fKey == kEmptyAtlasRowKey || this->searchByKey(fRows[i].fKey) >= 0);
    }

    // Our count of locks should equal the sum of row locks, unless we ran out of rows and flushed,
    // in which case we'll have one more lock than recorded in the rows (to represent the pending
    // lock of a row; which ensures we don't unlock the texture prematurely).
    SkASSERT(rowLocks == fLockedRows || rowLocks + 1 == fLockedRows);

    // We should have one lru entry for each free row
    SkASSERT(freeRows == lruCount);

    // If we have locked rows, we should have a locked texture, otherwise
    // it should be unlocked
    if (fLockedRows == 0) {
        SkASSERT(!fTexContext);
    } else {
        SkASSERT(fTexContext);
    }
}
#endif
<commit_msg>Fix memory leak: adopt rather than ref GrTexture* in GrTextureStripAtlas<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrTextureStripAtlas.h"
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrSurfaceContext.h"
#include "SkGr.h"
#include "SkPixelRef.h"
#include "SkTSearch.h"

#ifdef SK_DEBUG
    #define VALIDATE this->validate()
#else
    #define VALIDATE
#endif

class GrTextureStripAtlas::Hash : public SkTDynamicHash<GrTextureStripAtlas::AtlasEntry,
                                                        GrTextureStripAtlas::Desc> {};

int32_t GrTextureStripAtlas::gCacheCount = 0;

GrTextureStripAtlas::Hash* GrTextureStripAtlas::gAtlasCache = nullptr;

GrTextureStripAtlas::Hash* GrTextureStripAtlas::GetCache() {

    if (nullptr == gAtlasCache) {
        gAtlasCache = new Hash;
    }

    return gAtlasCache;
}

// Remove the specified atlas from the cache
void GrTextureStripAtlas::CleanUp(const GrContext*, void* info) {
    SkASSERT(info);

    AtlasEntry* entry = static_cast<AtlasEntry*>(info);

    // remove the cache entry
    GetCache()->remove(entry->fDesc);

    // remove the actual entry
    delete entry;

    if (0 == GetCache()->count()) {
        delete gAtlasCache;
        gAtlasCache = nullptr;
    }
}

GrTextureStripAtlas* GrTextureStripAtlas::GetAtlas(const GrTextureStripAtlas::Desc& desc) {
    AtlasEntry* entry = GetCache()->find(desc);
    if (nullptr == entry) {
        entry = new AtlasEntry;

        entry->fAtlas = new GrTextureStripAtlas(desc);
        entry->fDesc = desc;

        desc.fContext->addCleanUp(CleanUp, entry);

        GetCache()->add(entry);
    }

    return entry->fAtlas;
}

GrTextureStripAtlas::GrTextureStripAtlas(GrTextureStripAtlas::Desc desc)
    : fCacheKey(sk_atomic_inc(&gCacheCount))
    , fLockedRows(0)
    , fDesc(desc)
    , fNumRows(desc.fHeight / desc.fRowHeight)
    , fRows(new AtlasRow[fNumRows])
    , fLRUFront(nullptr)
    , fLRUBack(nullptr) {
    SkASSERT(fNumRows * fDesc.fRowHeight == fDesc.fHeight);
    this->initLRU();
    fNormalizedYHeight = SK_Scalar1 / fDesc.fHeight;
    VALIDATE;
}

GrTextureStripAtlas::~GrTextureStripAtlas() { delete[] fRows; }

int GrTextureStripAtlas::lockRow(const SkBitmap& bitmap) {
    VALIDATE;
    if (0 == fLockedRows) {
        this->lockTexture();
        if (!fTexContext) {
            return -1;
        }
    }

    int key = bitmap.getGenerationID();
    int rowNumber = -1;
    int index = this->searchByKey(key);

    if (index >= 0) {
        // We already have the data in a row, so we can just return that row
        AtlasRow* row = fKeyTable[index];
        if (0 == row->fLocks) {
            this->removeFromLRU(row);
        }
        ++row->fLocks;
        ++fLockedRows;

        // Since all the rows are always stored in a contiguous array, we can save the memory
        // required for storing row numbers and just compute it with some pointer arithmetic
        rowNumber = static_cast<int>(row - fRows);
    } else {
        // ~index is the index where we will insert the new key to keep things sorted
        index = ~index;

        // We don't have this data cached, so pick the least recently used row to copy into
        AtlasRow* row = this->getLRU();

        ++fLockedRows;

        if (nullptr == row) {
            // force a flush, which should unlock all the rows; then try again
            fDesc.fContext->flush();
            row = this->getLRU();
            if (nullptr == row) {
                --fLockedRows;
                return -1;
            }
        }

        this->removeFromLRU(row);

        uint32_t oldKey = row->fKey;

        // If we are writing into a row that already held bitmap data, we need to remove the
        // reference to that genID which is stored in our sorted table of key values.
        if (oldKey != kEmptyAtlasRowKey) {

            // Find the entry in the list; if it's before the index where we plan on adding the new
            // entry, we decrement since it will shift elements ahead of it back by one.
            int oldIndex = this->searchByKey(oldKey);
            if (oldIndex < index) {
                --index;
            }

            fKeyTable.remove(oldIndex);
        }

        row->fKey = key;
        row->fLocks = 1;
        fKeyTable.insert(index, 1, &row);
        rowNumber = static_cast<int>(row - fRows);

        SkAutoLockPixels lock(bitmap);

        SkASSERT(bitmap.width() == fDesc.fWidth);
        SkASSERT(bitmap.height() == fDesc.fRowHeight);

        // Pass in the kDontFlush flag, since we know we're writing to a part of this texture
        // that is not currently in use
        fTexContext->writePixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(),
                                 0, rowNumber * fDesc.fRowHeight,
                                 GrContext::kDontFlush_PixelOpsFlag);
    }

    SkASSERT(rowNumber >= 0);
    VALIDATE;
    return rowNumber;
}

sk_sp<GrTextureProxy> GrTextureStripAtlas::asTextureProxyRef() const {
    return fTexContext->asTextureProxyRef();
}

void GrTextureStripAtlas::unlockRow(int row) {
    VALIDATE;
    --fRows[row].fLocks;
    --fLockedRows;
    SkASSERT(fRows[row].fLocks >= 0 && fLockedRows >= 0);
    if (0 == fRows[row].fLocks) {
        this->appendLRU(fRows + row);
    }
    if (0 == fLockedRows) {
        this->unlockTexture();
    }
    VALIDATE;
}

GrTextureStripAtlas::AtlasRow* GrTextureStripAtlas::getLRU() {
    // Front is least-recently-used
    AtlasRow* row = fLRUFront;
    return row;
}

void GrTextureStripAtlas::lockTexture() {
    GrSurfaceDesc texDesc;
    texDesc.fWidth = fDesc.fWidth;
    texDesc.fHeight = fDesc.fHeight;
    texDesc.fConfig = fDesc.fConfig;
    texDesc.fIsMipMapped = false;

    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
    GrUniqueKey key;
    GrUniqueKey::Builder builder(&key, kDomain, 1);
    builder[0] = static_cast<uint32_t>(fCacheKey);
    builder.finish();

    // MDB TODO (caching): this side-steps the issue of proxies with unique IDs
    sk_sp<GrTexture> texture(fDesc.fContext->textureProvider()->findAndRefTextureByUniqueKey(key));
    if (!texture) {
        texture.reset(fDesc.fContext->textureProvider()->createTexture(texDesc, SkBudgeted::kYes,
                                                                       nullptr, 0));
        if (!texture) {
            return;
        }

        // We will be issuing writes to the surface using kDontFlush_PixelOpsFlag, so we
        // need to make sure any existing IO is flushed
        fDesc.fContext->flushSurfaceIO(texture.get());
        fDesc.fContext->textureProvider()->assignUniqueKeyToTexture(key, texture.get());
        // This is a new texture, so all of our cache info is now invalid
        this->initLRU();
        fKeyTable.rewind();
    }
    SkASSERT(texture);
    fTexContext = fDesc.fContext->contextPriv().makeWrappedSurfaceContext(std::move(texture));
}

void GrTextureStripAtlas::unlockTexture() {
    SkASSERT(fTexContext && 0 == fLockedRows);
    fTexContext.reset();
}

void GrTextureStripAtlas::initLRU() {
    fLRUFront = nullptr;
    fLRUBack = nullptr;
    // Initially all the rows are in the LRU list
    for (int i = 0; i < fNumRows; ++i) {
        fRows[i].fKey = kEmptyAtlasRowKey;
        fRows[i].fNext = nullptr;
        fRows[i].fPrev = nullptr;
        this->appendLRU(fRows + i);
    }
    SkASSERT(nullptr == fLRUFront || nullptr == fLRUFront->fPrev);
    SkASSERT(nullptr == fLRUBack || nullptr == fLRUBack->fNext);
}

void GrTextureStripAtlas::appendLRU(AtlasRow* row) {
    SkASSERT(nullptr == row->fPrev && nullptr == row->fNext);
    if (nullptr == fLRUFront && nullptr == fLRUBack) {
        fLRUFront = row;
        fLRUBack = row;
    } else {
        row->fPrev = fLRUBack;
        fLRUBack->fNext = row;
        fLRUBack = row;
    }
}

void GrTextureStripAtlas::removeFromLRU(AtlasRow* row) {
    SkASSERT(row);
    if (row->fNext && row->fPrev) {
        row->fPrev->fNext = row->fNext;
        row->fNext->fPrev = row->fPrev;
    } else {
        if (nullptr == row->fNext) {
            SkASSERT(row == fLRUBack);
            fLRUBack = row->fPrev;
            if (fLRUBack) {
                fLRUBack->fNext = nullptr;
            }
        }
        if (nullptr == row->fPrev) {
            SkASSERT(row == fLRUFront);
            fLRUFront = row->fNext;
            if (fLRUFront) {
                fLRUFront->fPrev = nullptr;
            }
        }
    }
    row->fNext = nullptr;
    row->fPrev = nullptr;
}

int GrTextureStripAtlas::searchByKey(uint32_t key) {
    AtlasRow target;
    target.fKey = key;
    return SkTSearch<const AtlasRow,
                     GrTextureStripAtlas::KeyLess>((const AtlasRow**)fKeyTable.begin(),
                                                   fKeyTable.count(),
                                                   &target,
                                                   sizeof(AtlasRow*));
}

#ifdef SK_DEBUG
void GrTextureStripAtlas::validate() {

    // Our key table should be sorted
    uint32_t prev = 1 > fKeyTable.count() ? 0 : fKeyTable[0]->fKey;
    for (int i = 1; i < fKeyTable.count(); ++i) {
        SkASSERT(prev < fKeyTable[i]->fKey);
        SkASSERT(fKeyTable[i]->fKey != kEmptyAtlasRowKey);
        prev = fKeyTable[i]->fKey;
    }

    int lruCount = 0;
    // Validate LRU pointers, and count LRU entries
    SkASSERT(nullptr == fLRUFront || nullptr == fLRUFront->fPrev);
    SkASSERT(nullptr == fLRUBack  || nullptr == fLRUBack->fNext);
    for (AtlasRow* r = fLRUFront; r != nullptr; r = r->fNext) {
        if (nullptr == r->fNext) {
            SkASSERT(r == fLRUBack);
        } else {
            SkASSERT(r->fNext->fPrev == r);
        }
        ++lruCount;
    }

    int rowLocks = 0;
    int freeRows = 0;

    for (int i = 0; i < fNumRows; ++i) {
        rowLocks += fRows[i].fLocks;
        if (0 == fRows[i].fLocks) {
            ++freeRows;
            bool inLRU = false;
            // Step through the LRU and make sure it's present
            for (AtlasRow* r = fLRUFront; r != nullptr; r = r->fNext) {
                if (r == &fRows[i]) {
                    inLRU = true;
                    break;
                }
            }
            SkASSERT(inLRU);
        } else {
            // If we are locked, we should have a key
            SkASSERT(kEmptyAtlasRowKey != fRows[i].fKey);
        }

        // If we have a key != kEmptyAtlasRowKey, it should be in the key table
        SkASSERT(fRows[i].fKey == kEmptyAtlasRowKey || this->searchByKey(fRows[i].fKey) >= 0);
    }

    // Our count of locks should equal the sum of row locks, unless we ran out of rows and flushed,
    // in which case we'll have one more lock than recorded in the rows (to represent the pending
    // lock of a row; which ensures we don't unlock the texture prematurely).
    SkASSERT(rowLocks == fLockedRows || rowLocks + 1 == fLockedRows);

    // We should have one lru entry for each free row
    SkASSERT(freeRows == lruCount);

    // If we have locked rows, we should have a locked texture, otherwise
    // it should be unlocked
    if (fLockedRows == 0) {
        SkASSERT(!fTexContext);
    } else {
        SkASSERT(fTexContext);
    }
}
#endif
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the $MODULE$ of the Qt Toolkit.
**
** $TROLLTECH_DUAL_EMBEDDED_LICENSE$
**
****************************************************************************/

#include <qglobal.h> // for Q_WS_WIN define (non-PCH)

#include <QtGui/qpaintdevice.h>
#include <private/qwidget_p.h>
#include "qwindowsurface_s60_p.h"
#include "qt_s60_p.h"
#include "private/qdrawhelper_p.h"

QT_BEGIN_NAMESPACE

struct QS60WindowSurfacePrivate
{
    QImage device;
    CFbsBitmap *bitmap;
    uchar* bytes;

    // Since only one CFbsBitmap is allowed to be locked at a time, this is static.
    static QS60WindowSurface* lockedSurface;
};
QS60WindowSurface* QS60WindowSurfacePrivate::lockedSurface = NULL;

QS60WindowSurface::QS60WindowSurface(QWidget* widget)
    : QWindowSurface(widget), d_ptr(new QS60WindowSurfacePrivate)
{
    d_ptr->bytes = 0;
    d_ptr->bitmap = 0;

    TDisplayMode mode = S60->screenDevice()->DisplayMode();
    bool isOpaque = qt_widget_private(widget)->isOpaque;
    if (mode == EColor16MA && isOpaque)
        mode = EColor16MU; // Faster since 16MU -> 16MA is typically accelerated
    else if (mode == EColor16MU && !isOpaque)
        mode = EColor16MA; // Try for transparency anyway

    // We create empty CFbsBitmap here -> it will be resized in setGeometry
    d_ptr->bitmap = new (ELeave) CFbsBitmap;
    User::LeaveIfError( d_ptr->bitmap->Create(TSize(0, 0), mode ) );

    updatePaintDeviceOnBitmap();

    setStaticContentsSupport(true);
}

QS60WindowSurface::~QS60WindowSurface()
{
    // Ensure that locking and unlocking of this surface were symmetrical
    Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface != this);

    delete d_ptr->bitmap;
    delete d_ptr;
}

void QS60WindowSurface::beginPaint(const QRegion &rgn)
{
    if(!d_ptr->bitmap)
        return;

    Q_ASSERT(!QS60WindowSurfacePrivate::lockedSurface);
    QS60WindowSurfacePrivate::lockedSurface = this;
    lockBitmapHeap();

    if (!qt_widget_private(window())->isOpaque) {
        QRgb *data = reinterpret_cast<QRgb *>(d_ptr->device.bits());
        const int row_stride = d_ptr->device.bytesPerLine() / 4;

        const QVector<QRect> rects = rgn.rects();
        for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
            const int x_start = it->x();
            const int width = it->width();

            const int y_start = it->y();
            const int height = it->height();

            QRgb *row = data + row_stride * y_start;
            for (int y = 0; y < height; ++y) {
                qt_memfill(row + x_start, 0U, width);
                row += row_stride;
            }
        }
    }
}

void QS60WindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &)
{
    const QVector<QRect> subRects = region.rects();
    for (int i = 0; i < subRects.count(); ++i) {
        TRect tr = qt_QRect2TRect(subRects[i]);
        widget->winId()->DrawNow(tr);
    }
}

bool QS60WindowSurface::scroll(const QRegion &area, int dx, int dy)
{
    QRect rect = area.boundingRect();

    if (dx == 0 && dy == 0)
        return false;

    if (d_ptr->device.isNull())
        return false;

    CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(d_ptr->bitmap);
    CBitmapContext *bitmapContext;
    TInt err = bitmapDevice->CreateBitmapContext(bitmapContext);
    if (err != KErrNone) {
        CBase::Delete(bitmapDevice);
        return false;
    }
    bitmapContext->CopyRect(TPoint(dx, dy), qt_QRect2TRect(rect));
    CBase::Delete(bitmapContext);
    CBase::Delete(bitmapDevice);
    return true;
}

void QS60WindowSurface::endPaint(const QRegion &rgn)
{
    if(!d_ptr->bitmap)
        return;

    Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface);
    unlockBitmapHeap();
    QS60WindowSurfacePrivate::lockedSurface = NULL;
}

QPaintDevice* QS60WindowSurface::paintDevice()
{
    return &d_ptr->device;
}

void QS60WindowSurface::setGeometry(const QRect& rect)
{
    if (rect == geometry())
        return;

    TRect nativeRect(qt_QRect2TRect(rect));
    User::LeaveIfError(d_ptr->bitmap->Resize(nativeRect.Size()));

    updatePaintDeviceOnBitmap();

    QWindowSurface::setGeometry(rect);
}

void QS60WindowSurface::lockBitmapHeap()
{
    if (!QS60WindowSurfacePrivate::lockedSurface)
        return;

    // Get some local variables to make later code lines more clear to read
    CFbsBitmap*& bitmap = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap;
    QImage& device = QS60WindowSurfacePrivate::lockedSurface->d_ptr->device;
    uchar*& bytes = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bytes;

    bitmap->LockHeap();
    uchar *newBytes = (uchar*)bitmap->DataAddress();
    if (newBytes != bytes) {
        bytes = newBytes;

        // Get some values for QImage creation
        TDisplayMode mode  = bitmap->DisplayMode();
        if (mode == EColor16MA
            && qt_widget_private(QS60WindowSurfacePrivate::lockedSurface->window())->isOpaque)
            mode = EColor16MU;
        QImage::Format format = qt_TDisplayMode2Format( mode );
        TSize bitmapSize = bitmap->SizeInPixels();
        int bytesPerLine = CFbsBitmap::ScanLineLength( bitmapSize.iWidth, mode);

        device = QImage( bytes, bitmapSize.iWidth, bitmapSize.iHeight, bytesPerLine, format );
    }
}

void QS60WindowSurface::unlockBitmapHeap()
{
    if (!QS60WindowSurfacePrivate::lockedSurface)
        return;

    QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap->UnlockHeap();
}

void QS60WindowSurface::updatePaintDeviceOnBitmap()
{
    // This forces the actual device to be updated based on CFbsBitmap
    beginPaint(QRegion());
    endPaint(QRegion());
}

CFbsBitmap *QS60WindowSurface::symbianBitmap() const
{
    return d_ptr->bitmap;
}

QT_END_NAMESPACE
<commit_msg>Small optimization when hiding windows.<commit_after>/****************************************************************************
**
** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the $MODULE$ of the Qt Toolkit.
**
** $TROLLTECH_DUAL_EMBEDDED_LICENSE$
**
****************************************************************************/

#include <qglobal.h> // for Q_WS_WIN define (non-PCH)

#include <QtGui/qpaintdevice.h>
#include <private/qwidget_p.h>
#include "qwindowsurface_s60_p.h"
#include "qt_s60_p.h"
#include "private/qdrawhelper_p.h"

QT_BEGIN_NAMESPACE

struct QS60WindowSurfacePrivate
{
    QImage device;
    CFbsBitmap *bitmap;
    uchar* bytes;

    // Since only one CFbsBitmap is allowed to be locked at a time, this is static.
    static QS60WindowSurface* lockedSurface;
};
QS60WindowSurface* QS60WindowSurfacePrivate::lockedSurface = NULL;

QS60WindowSurface::QS60WindowSurface(QWidget* widget)
    : QWindowSurface(widget), d_ptr(new QS60WindowSurfacePrivate)
{
    d_ptr->bytes = 0;
    d_ptr->bitmap = 0;

    TDisplayMode mode = S60->screenDevice()->DisplayMode();
    bool isOpaque = qt_widget_private(widget)->isOpaque;
    if (mode == EColor16MA && isOpaque)
        mode = EColor16MU; // Faster since 16MU -> 16MA is typically accelerated
    else if (mode == EColor16MU && !isOpaque)
        mode = EColor16MA; // Try for transparency anyway

    // We create empty CFbsBitmap here -> it will be resized in setGeometry
    d_ptr->bitmap = new (ELeave) CFbsBitmap;
    User::LeaveIfError( d_ptr->bitmap->Create(TSize(0, 0), mode ) );

    updatePaintDeviceOnBitmap();

    setStaticContentsSupport(true);
}

QS60WindowSurface::~QS60WindowSurface()
{
    // Ensure that locking and unlocking of this surface were symmetrical
    Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface != this);

    delete d_ptr->bitmap;
    delete d_ptr;
}

void QS60WindowSurface::beginPaint(const QRegion &rgn)
{
    if(!d_ptr->bitmap)
        return;

    Q_ASSERT(!QS60WindowSurfacePrivate::lockedSurface);
    QS60WindowSurfacePrivate::lockedSurface = this;
    lockBitmapHeap();

    if (!qt_widget_private(window())->isOpaque) {
        QRgb *data = reinterpret_cast<QRgb *>(d_ptr->device.bits());
        const int row_stride = d_ptr->device.bytesPerLine() / 4;

        const QVector<QRect> rects = rgn.rects();
        for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
            const int x_start = it->x();
            const int width = it->width();

            const int y_start = it->y();
            const int height = it->height();

            QRgb *row = data + row_stride * y_start;
            for (int y = 0; y < height; ++y) {
                qt_memfill(row + x_start, 0U, width);
                row += row_stride;
            }
        }
    }
}

void QS60WindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &)
{
    const QVector<QRect> subRects = region.rects();
    for (int i = 0; i < subRects.count(); ++i) {
        TRect tr = qt_QRect2TRect(subRects[i]);
        widget->winId()->DrawNow(tr);
    }
}

bool QS60WindowSurface::scroll(const QRegion &area, int dx, int dy)
{
    QRect rect = area.boundingRect();

    if (dx == 0 && dy == 0)
        return false;

    if (d_ptr->device.isNull())
        return false;

    CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(d_ptr->bitmap);
    CBitmapContext *bitmapContext;
    TInt err = bitmapDevice->CreateBitmapContext(bitmapContext);
    if (err != KErrNone) {
        CBase::Delete(bitmapDevice);
        return false;
    }
    bitmapContext->CopyRect(TPoint(dx, dy), qt_QRect2TRect(rect));
    CBase::Delete(bitmapContext);
    CBase::Delete(bitmapDevice);
    return true;
}

void QS60WindowSurface::endPaint(const QRegion &rgn)
{
    if(!d_ptr->bitmap)
        return;

    Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface);
    unlockBitmapHeap();
    QS60WindowSurfacePrivate::lockedSurface = NULL;
}

QPaintDevice* QS60WindowSurface::paintDevice()
{
    return &d_ptr->device;
}

void QS60WindowSurface::setGeometry(const QRect& rect)
{
    if (rect == geometry())
        return;

    QWindowSurface::setGeometry(rect);

    TRect nativeRect(qt_QRect2TRect(rect));
    User::LeaveIfError(d_ptr->bitmap->Resize(nativeRect.Size()));

    if (!rect.isNull())
        updatePaintDeviceOnBitmap();
}

void QS60WindowSurface::lockBitmapHeap()
{
    if (!QS60WindowSurfacePrivate::lockedSurface)
        return;

    // Get some local variables to make later code lines more clear to read
    CFbsBitmap*& bitmap = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap;
    QImage& device = QS60WindowSurfacePrivate::lockedSurface->d_ptr->device;
    uchar*& bytes = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bytes;

    bitmap->LockHeap();
    uchar *newBytes = (uchar*)bitmap->DataAddress();
    if (newBytes != bytes) {
        bytes = newBytes;

        // Get some values for QImage creation
        TDisplayMode mode  = bitmap->DisplayMode();
        if (mode == EColor16MA
            && qt_widget_private(QS60WindowSurfacePrivate::lockedSurface->window())->isOpaque)
            mode = EColor16MU;
        QImage::Format format = qt_TDisplayMode2Format( mode );
        TSize bitmapSize = bitmap->SizeInPixels();
        int bytesPerLine = CFbsBitmap::ScanLineLength( bitmapSize.iWidth, mode);

        device = QImage( bytes, bitmapSize.iWidth, bitmapSize.iHeight, bytesPerLine, format );
    }
}

void QS60WindowSurface::unlockBitmapHeap()
{
    if (!QS60WindowSurfacePrivate::lockedSurface)
        return;

    QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap->UnlockHeap();
}

void QS60WindowSurface::updatePaintDeviceOnBitmap()
{
    // This forces the actual device to be updated based on CFbsBitmap
    beginPaint(QRegion());
    endPaint(QRegion());
}

CFbsBitmap *QS60WindowSurface::symbianBitmap() const
{
    return d_ptr->bitmap;
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/path_service.h"
#include "base/task.h"
#include "chrome/browser/ui/views/html_dialog_view.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/webui/web_ui.h"
#include "content/common/notification_registrar.h"
#include "net/test/test_server.h"

namespace {

typedef DOMElementProxy::By By;

class FileBrowseBrowserTest : public InProcessBrowserTest {
 public:
   FileBrowseBrowserTest() {
     EnableDOMAutomation();
   }
};

class FileBrowseUiObserver : public NotificationObserver {
 public:
  FileBrowseUiObserver() : file_browse_tab_(NULL), is_waiting_(false) {
    registrar_.Add(this, NotificationType::LOAD_STOP,
                   NotificationService::AllSources());
    registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
                   NotificationService::AllSources());
  }

  void WaitForFileBrowseLoad() {
    if (file_browse_tab_ == NULL) {
      is_waiting_ = true;
      ui_test_utils::RunMessageLoop();
    }
  }

  // File browse tab deletion is a non-nestable task and BrowserTest would
  // not get related notification because test body runs in a task already.
  // Uses a periodical check of the dialog window to implement the wait.
  void WaitForFileBrowseClose() {
    if (file_browse_tab_ != NULL) {
      is_waiting_ = true;
      ui_test_utils::RunMessageLoop();
    }
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    if (type == NotificationType::LOAD_STOP) {
      NavigationController* controller =
          Source<NavigationController>(source).ptr();

      if (controller) {
        TabContents* tab_contents = controller->tab_contents();
        if (tab_contents &&
            tab_contents->GetURL().SchemeIs(chrome::kChromeUIScheme) &&
            tab_contents->GetURL().host() == chrome::kChromeUIFileBrowseHost) {
          file_browse_tab_ = tab_contents;

          if (is_waiting_) {
            is_waiting_ = false;
            MessageLoopForUI::current()->Quit();
          }
        }
      }
    } else if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
      TabContents* tab_contents = Source<TabContents>(source).ptr();
      if (file_browse_tab_ == tab_contents) {
        file_browse_tab_ = NULL;

        if (is_waiting_) {
          is_waiting_ = false;
          MessageLoopForUI::current()->Quit();
        }
      }
    }
  }

  TabContents* file_browse_tab() {
    return file_browse_tab_;
  }

  WebUI* file_browse_ui() {
    return file_browse_tab_ ? file_browse_tab_->render_manager()->web_ui() :
                              NULL;
  }

 private:
  NotificationRegistrar registrar_;
  TabContents* file_browse_tab_;
  bool is_waiting_;

  DISALLOW_COPY_AND_ASSIGN(FileBrowseUiObserver);
};

IN_PROC_BROWSER_TEST_F(FileBrowseBrowserTest, InputFileTriggerFileBrowse) {
  ASSERT_TRUE(test_server()->Start());
  ui_test_utils::NavigateToURL(browser(),
                               test_server()->GetURL("files/input_file.html"));

  DOMElementProxyRef doc = ui_test_utils::GetActiveDOMDocument(browser());

  DOMElementProxyRef input_file = doc->FindElement(By::Selectors(".single"));
  ASSERT_TRUE(input_file);

  // Creates FileBrowseUiObserver before we click.
  FileBrowseUiObserver observer;

  // Click on the input control. This should bring up the FileBrowseUI.
  input_file->Click();

  observer.WaitForFileBrowseLoad();
  WebUI* file_browser_ui = observer.file_browse_ui();
  ASSERT_TRUE(file_browser_ui);

  file_browser_ui->CallJavascriptFunction("dialogCancelClick");

  observer.WaitForFileBrowseClose();
}

}  // namespace
<commit_msg>Disabled obsolete test, we should rewrite this to match the new code.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/path_service.h"
#include "base/task.h"
#include "chrome/browser/ui/views/html_dialog_view.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/webui/web_ui.h"
#include "content/common/notification_registrar.h"
#include "net/test/test_server.h"

namespace {

typedef DOMElementProxy::By By;

class FileBrowseBrowserTest : public InProcessBrowserTest {
 public:
   FileBrowseBrowserTest() {
     EnableDOMAutomation();
   }
};

class FileBrowseUiObserver : public NotificationObserver {
 public:
  FileBrowseUiObserver() : file_browse_tab_(NULL), is_waiting_(false) {
    registrar_.Add(this, NotificationType::LOAD_STOP,
                   NotificationService::AllSources());
    registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
                   NotificationService::AllSources());
  }

  void WaitForFileBrowseLoad() {
    if (file_browse_tab_ == NULL) {
      is_waiting_ = true;
      ui_test_utils::RunMessageLoop();
    }
  }

  // File browse tab deletion is a non-nestable task and BrowserTest would
  // not get related notification because test body runs in a task already.
  // Uses a periodical check of the dialog window to implement the wait.
  void WaitForFileBrowseClose() {
    if (file_browse_tab_ != NULL) {
      is_waiting_ = true;
      ui_test_utils::RunMessageLoop();
    }
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    if (type == NotificationType::LOAD_STOP) {
      NavigationController* controller =
          Source<NavigationController>(source).ptr();

      if (controller) {
        TabContents* tab_contents = controller->tab_contents();
        if (tab_contents &&
            tab_contents->GetURL().SchemeIs(chrome::kChromeUIScheme) &&
            tab_contents->GetURL().host() == chrome::kChromeUIFileBrowseHost) {
          file_browse_tab_ = tab_contents;

          if (is_waiting_) {
            is_waiting_ = false;
            MessageLoopForUI::current()->Quit();
          }
        }
      }
    } else if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
      TabContents* tab_contents = Source<TabContents>(source).ptr();
      if (file_browse_tab_ == tab_contents) {
        file_browse_tab_ = NULL;

        if (is_waiting_) {
          is_waiting_ = false;
          MessageLoopForUI::current()->Quit();
        }
      }
    }
  }

  TabContents* file_browse_tab() {
    return file_browse_tab_;
  }

  WebUI* file_browse_ui() {
    return file_browse_tab_ ? file_browse_tab_->render_manager()->web_ui() :
                              NULL;
  }

 private:
  NotificationRegistrar registrar_;
  TabContents* file_browse_tab_;
  bool is_waiting_;

  DISALLOW_COPY_AND_ASSIGN(FileBrowseUiObserver);
};

IN_PROC_BROWSER_TEST_F(FileBrowseBrowserTest,
                       DISABLED_InputFileTriggerFileBrowse) {
  ASSERT_TRUE(test_server()->Start());
  ui_test_utils::NavigateToURL(browser(),
                               test_server()->GetURL("files/input_file.html"));

  DOMElementProxyRef doc = ui_test_utils::GetActiveDOMDocument(browser());

  DOMElementProxyRef input_file = doc->FindElement(By::Selectors(".single"));
  ASSERT_TRUE(input_file);

  // Creates FileBrowseUiObserver before we click.
  FileBrowseUiObserver observer;

  // Click on the input control. This should bring up the FileBrowseUI.
  input_file->Click();

  observer.WaitForFileBrowseLoad();
  WebUI* file_browser_ui = observer.file_browse_ui();
  ASSERT_TRUE(file_browser_ui);

  file_browser_ui->CallJavascriptFunction("dialogCancelClick");

  observer.WaitForFileBrowseClose();
}

}  // namespace
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, The University of Oxford
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the University of Oxford nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "utility/test/Test_Timer.h"
#include "utility/oskar_timer_functions.h"

void Test_Timer::test()
{
    oskar_Timer t_cuda, t_omp, t_native;
    oskar_timer_create(&t_native, OSKAR_TIMER_NATIVE);
    oskar_timer_create(&t_cuda, OSKAR_TIMER_CUDA);
    oskar_timer_create(&t_omp, OSKAR_TIMER_OMP);

    // Time a sleep(1).
    oskar_timer_resume(&t_native);
    oskar_timer_resume(&t_cuda);
    oskar_timer_resume(&t_omp);
    sleep(1);
    oskar_timer_pause(&t_native);
    oskar_timer_pause(&t_cuda);
    oskar_timer_pause(&t_omp);

    // Don't time this sleep.
    sleep(1);

    // Time another sleep(1).
    oskar_timer_resume(&t_native);
    oskar_timer_resume(&t_cuda);
    oskar_timer_resume(&t_omp);
    sleep(1);
    oskar_timer_pause(&t_native);
    oskar_timer_pause(&t_cuda);
    oskar_timer_pause(&t_omp);

    double elapsed_native = oskar_timer_elapsed(&t_native);
    double elapsed_cuda = oskar_timer_elapsed(&t_cuda);
    double elapsed_omp = oskar_timer_elapsed(&t_omp);
//    printf("Timings -- Native: %.5f, CUDA: %.5f, OpenMP: %.5f\n",
//            elapsed_native, elapsed_cuda, elapsed_omp);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(elapsed_native, elapsed_cuda, 5e-3);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(elapsed_native, elapsed_omp, 5e-3);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, elapsed_native, 1e-2);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, elapsed_cuda, 1e-2);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, elapsed_omp, 1e-2);

    oskar_timer_destroy(&t_native);
    oskar_timer_destroy(&t_cuda);
    oskar_timer_destroy(&t_omp);
}

void Test_Timer::test_performance()
{
    oskar_Timer t_native, t_cuda, t_omp, t;
    oskar_timer_create(&t, OSKAR_TIMER_NATIVE);
    oskar_timer_create(&t_native, OSKAR_TIMER_NATIVE);
    oskar_timer_create(&t_cuda, OSKAR_TIMER_CUDA);
    oskar_timer_create(&t_omp, OSKAR_TIMER_OMP);
    int runs = 1000;
    printf("\n");

    oskar_timer_start(&t);
    for (int i = 0; i < runs; ++i)
    {
        oskar_timer_resume(&t_cuda);
        oskar_timer_pause(&t_cuda);
    }
    printf("  CUDA timer overhead: %.4e s.\n", oskar_timer_elapsed(&t) / runs);

    oskar_timer_start(&t);
    for (int i = 0; i < runs; ++i)
    {
        oskar_timer_resume(&t_omp);
        oskar_timer_pause(&t_omp);
    }
    printf("OpenMP timer overhead: %.4e s.\n", oskar_timer_elapsed(&t) / runs);

    oskar_timer_start(&t);
    for (int i = 0; i < runs; ++i)
    {
        oskar_timer_resume(&t_native);
        oskar_timer_pause(&t_native);
    }
    printf("Native timer overhead: %.4e s.\n", oskar_timer_elapsed(&t) / runs);

    oskar_timer_destroy(&t);
    oskar_timer_destroy(&t_native);
    oskar_timer_destroy(&t_cuda);
    oskar_timer_destroy(&t_omp);
}
<commit_msg>added header for the sleep function - needed for g++-4.7<commit_after>/*
 * Copyright (c) 2013, The University of Oxford
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the University of Oxford nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "utility/test/Test_Timer.h"
#include "utility/oskar_timer_functions.h"
#include <unistd.h> // Note: this is a GNU compiler only header and needed
                    // for sleep() for some versions of g++ (tested with v 4.7)
                    // On windows this function is defined in windows.h
                    // with an argument in milliseconds rather than seconds.

void Test_Timer::test()
{
    oskar_Timer t_cuda, t_omp, t_native;
    oskar_timer_create(&t_native, OSKAR_TIMER_NATIVE);
    oskar_timer_create(&t_cuda, OSKAR_TIMER_CUDA);
    oskar_timer_create(&t_omp, OSKAR_TIMER_OMP);

    // Time a sleep(1).
    oskar_timer_resume(&t_native);
    oskar_timer_resume(&t_cuda);
    oskar_timer_resume(&t_omp);
    sleep(1);
    oskar_timer_pause(&t_native);
    oskar_timer_pause(&t_cuda);
    oskar_timer_pause(&t_omp);

    // Don't time this sleep.
    sleep(1);

    // Time another sleep(1).
    oskar_timer_resume(&t_native);
    oskar_timer_resume(&t_cuda);
    oskar_timer_resume(&t_omp);
    sleep(1);
    oskar_timer_pause(&t_native);
    oskar_timer_pause(&t_cuda);
    oskar_timer_pause(&t_omp);

    double elapsed_native = oskar_timer_elapsed(&t_native);
    double elapsed_cuda = oskar_timer_elapsed(&t_cuda);
    double elapsed_omp = oskar_timer_elapsed(&t_omp);
//    printf("Timings -- Native: %.5f, CUDA: %.5f, OpenMP: %.5f\n",
//            elapsed_native, elapsed_cuda, elapsed_omp);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(elapsed_native, elapsed_cuda, 5e-3);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(elapsed_native, elapsed_omp, 5e-3);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, elapsed_native, 1e-2);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, elapsed_cuda, 1e-2);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, elapsed_omp, 1e-2);

    oskar_timer_destroy(&t_native);
    oskar_timer_destroy(&t_cuda);
    oskar_timer_destroy(&t_omp);
}

void Test_Timer::test_performance()
{
    oskar_Timer t_native, t_cuda, t_omp, t;
    oskar_timer_create(&t, OSKAR_TIMER_NATIVE);
    oskar_timer_create(&t_native, OSKAR_TIMER_NATIVE);
    oskar_timer_create(&t_cuda, OSKAR_TIMER_CUDA);
    oskar_timer_create(&t_omp, OSKAR_TIMER_OMP);
    int runs = 1000;
    printf("\n");

    oskar_timer_start(&t);
    for (int i = 0; i < runs; ++i)
    {
        oskar_timer_resume(&t_cuda);
        oskar_timer_pause(&t_cuda);
    }
    printf("  CUDA timer overhead: %.4e s.\n", oskar_timer_elapsed(&t) / runs);

    oskar_timer_start(&t);
    for (int i = 0; i < runs; ++i)
    {
        oskar_timer_resume(&t_omp);
        oskar_timer_pause(&t_omp);
    }
    printf("OpenMP timer overhead: %.4e s.\n", oskar_timer_elapsed(&t) / runs);

    oskar_timer_start(&t);
    for (int i = 0; i < runs; ++i)
    {
        oskar_timer_resume(&t_native);
        oskar_timer_pause(&t_native);
    }
    printf("Native timer overhead: %.4e s.\n", oskar_timer_elapsed(&t) / runs);

    oskar_timer_destroy(&t);
    oskar_timer_destroy(&t_native);
    oskar_timer_destroy(&t_cuda);
    oskar_timer_destroy(&t_omp);
}
<|endoftext|>


<commit_before>#include <QString>
#include <QDebug>

#include "qdeclarativeorganizeritem_p.h"
#include "qorganizeritemdetails.h"
#include "qdeclarativeorganizeritemdetail_p.h"
#include "qdeclarativeorganizeritemmetaobject_p.h"

QTM_USE_NAMESPACE
static OrganizerItemDetailNameMap qt_organizerItemDetailNameMap[] = {
   {"",               "",                false}
};

QDeclarativeOrganizerItemMetaObject::QDeclarativeOrganizerItemMetaObject(QObject* obj, const QOrganizerItem& item)
    :QDeclarativeOpenMetaObject(obj)
{
    setItem(item);
}

QDeclarativeOrganizerItemMetaObject::~QDeclarativeOrganizerItemMetaObject()
{

}

void QDeclarativeOrganizerItemMetaObject::getValue(int propId, void **a)
{
    qDebug() << "value for propId:" << propId;
    OrganizerItemDetailNameMap* detailMetaData = m_properties.value(propId);
    if (detailMetaData) {
        if (detailMetaData->group) {
            qDebug() << "name:" << detailMetaData->name;
            *reinterpret_cast< QDeclarativeListProperty<QDeclarativeOrganizerItemDetail>* >(a[0]) =
                    QDeclarativeListProperty<QDeclarativeOrganizerItemDetail>(object(), detailMetaData, detail_append, detail_count, detail_at, detail_clear);

        } else {
            foreach(QDeclarativeOrganizerItemDetail* cd, m_details) {
                if (cd->detail().definitionName() == detailMetaData->definitionName) {
                    *reinterpret_cast<QVariant *>(a[0]) = QVariant::fromValue(cd);
                }
            }
        }
    }

}

void QDeclarativeOrganizerItemMetaObject::setValue(int propId, void **a)
{
    OrganizerItemDetailNameMap* detailMetaData = m_properties.value(propId);
    if (detailMetaData) {
        if (!detailMetaData->group) {
            QVariant& v = *reinterpret_cast<QVariant *>(a[0]);
            QDeclarativeOrganizerItemDetail* detail = v.value<QDeclarativeOrganizerItemDetail*>();

            foreach(QDeclarativeOrganizerItemDetail* cd, m_details) {
                if (cd->detail().definitionName() == detailMetaData->definitionName) {
                    delete cd;
                    cd = detail;
                }
            }
        }
    }
}

int QDeclarativeOrganizerItemMetaObject::createProperty(const char * name,  const char *)
{

    const int detailCount = sizeof(qt_organizerItemDetailNameMap)/sizeof(OrganizerItemDetailNameMap);
    OrganizerItemDetailNameMap* detailMetaData = 0;

    for (int i = 0; i < detailCount; i++) {
        if (QString::fromLocal8Bit(qt_organizerItemDetailNameMap[i].name) == QString::fromLocal8Bit(name)) {
            detailMetaData = &qt_organizerItemDetailNameMap[i];
            break;
        }
    }

    if (detailMetaData) {
        int propId = -1;
        if (detailMetaData->group)
            propId = QDeclarativeOpenMetaObject::createProperty(name, "QDeclarativeListProperty<QDeclarativeOrganizerItemDetail>");
        else
            propId = QDeclarativeOpenMetaObject::createProperty(name, "QVariant");
        m_properties.insert(propId, detailMetaData);
        qDebug() << "createProperty:" << name << "propId:" << propId;
        return propId;
    }
    return -1;
}

QVariant QDeclarativeOrganizerItemMetaObject::detail(const QString& name)
{
    int propId = indexOfProperty(name.toLatin1());

    if (propId > 0)
        return property(propId).read(object());

    //Assume it's a detail definition name
    foreach(QDeclarativeOrganizerItemDetail* cd, m_details) {
        if (cd->detail().definitionName() == name) {
            return QVariant::fromValue(cd);
        }
    }
    return QVariant();
}

QVariant QDeclarativeOrganizerItemMetaObject::details(const QString& name)
{
    if (name.isEmpty()) {
        //return all
        return QVariant::fromValue(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail>(object(), m_details));
    } else {
        int propId = indexOfProperty(name.toLatin1());
        if (propId > 0)
            return property(propId).read(object());

        //Assume it's a detail definition name
        //TODO::customized details
        for (QHash<int, OrganizerItemDetailNameMap*>::ConstIterator iter = m_properties.constBegin(); iter != m_properties.constEnd(); iter++) {
            if (iter.value()->group && iter.value()->definitionName == name)
                return property(iter.key()).read(object());
        }
    }
    return QVariant();
}

void QDeclarativeOrganizerItemMetaObject::setItem(const QOrganizerItem& contact)
{
    m_item = contact;
    QList<QOrganizerItemDetail> details = m_item.details();
    m_details.clear();
    foreach (const QOrganizerItemDetail& detail, details) {
      QDeclarativeOrganizerItemDetail* cd = new QDeclarativeOrganizerItemDetail(object());

      cd->connect(cd, SIGNAL(fieldsChanged()), object(), SIGNAL(detailsChanged()));

      cd->setDetail(detail);
      m_details.append(cd);
    }
}

QOrganizerItem QDeclarativeOrganizerItemMetaObject::item()
{
    m_item.clearDetails();
    foreach ( QDeclarativeOrganizerItemDetail* cd, m_details) {
       QOrganizerItemDetail detail = cd->detail();
       m_item.saveDetail(&detail);
    }
    return m_item;
}

uint QDeclarativeOrganizerItemMetaObject::localId() const
{
    return qHash(m_item.localId());
}

uint QDeclarativeOrganizerItemMetaObject::itemId() const
{
    return qHash(m_item.id());
}

void QDeclarativeOrganizerItemMetaObject::detail_append(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail> *p, QDeclarativeOrganizerItemDetail *detail)
{
    OrganizerItemDetailNameMap* data = (OrganizerItemDetailNameMap*)(p->data);
    if (data) {
        QDeclarativeOrganizerItem* dc = qobject_cast<QDeclarativeOrganizerItem*>(p->object);
        if (dc && detail->detail().definitionName() == data->definitionName) {
            detail->connect(detail, SIGNAL(fieldsChanged()), dc, SIGNAL(detailsChanged()));
            dc->d->m_details.append(detail);
        }
    }
}

int  QDeclarativeOrganizerItemMetaObject::detail_count(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail> *p)
{
    OrganizerItemDetailNameMap* data = (OrganizerItemDetailNameMap*)(p->data);
    int count = 0;
    QDeclarativeOrganizerItem* dc = qobject_cast<QDeclarativeOrganizerItem*>(p->object);
    if (dc && data) {
        foreach(QDeclarativeOrganizerItemDetail* detail, dc->d->m_details) {
            if (detail->detail().definitionName() == data->definitionName)
                count++;
        }
    }
    return count;
}

QDeclarativeOrganizerItemDetail * QDeclarativeOrganizerItemMetaObject::detail_at(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail> *p, int idx)
{
    OrganizerItemDetailNameMap* data = (OrganizerItemDetailNameMap*)(p->data);
    QDeclarativeOrganizerItemDetail* detail = 0;
    QDeclarativeOrganizerItem* dc = qobject_cast<QDeclarativeOrganizerItem*>(p->object);
    if (dc && data) {
        int i = 0;
        foreach(QDeclarativeOrganizerItemDetail* cd,dc->d->m_details) {
            if (cd->detail().definitionName() == data->definitionName) {
                if (i == idx) {
                    detail = cd;
                    break;
                } else {
                    i++;
                }
            }
        }
    }
    return detail;
}

void  QDeclarativeOrganizerItemMetaObject::detail_clear(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail> *p)
{
    OrganizerItemDetailNameMap* data = (OrganizerItemDetailNameMap*)(p->data);
    QDeclarativeOrganizerItem* dc = qobject_cast<QDeclarativeOrganizerItem*>(p->object);
    if (dc && data) {
        foreach(QDeclarativeOrganizerItemDetail* cd, dc->d->m_details) {
            if (cd->detail().definitionName() == data->definitionName) {
                dc->d->m_details.removeAll(cd);
            }
        }
    }
}
<commit_msg>organizer declarative plugin:register item detail names and detail group names which could be accessed from qml<commit_after>#include <QString>
#include <QDebug>

#include "qdeclarativeorganizeritem_p.h"
#include "qorganizeritemdetails.h"
#include "qdeclarativeorganizeritemdetail_p.h"
#include "qdeclarativeorganizeritemmetaobject_p.h"

QTM_USE_NAMESPACE
#define Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(classname) \
    {QDeclarativeOrganizer##classname::DetailName.latin1(), QOrganizer##classname::DefinitionName.latin1(), false}

#define Q_DECLARATIVE_ORGANIZER_ITEM_DETAILGROUPNAME(classname) \
    {QDeclarativeOrganizer##classname::DetailGroupName.latin1(), QOrganizer##classname::DefinitionName.latin1(), true}

static OrganizerItemDetailNameMap qt_organizerItemDetailNameMap[] = {
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(EventTimeRange),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemComment),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILGROUPNAME(ItemComment),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemDescription),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemDisplayLabel),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemGuid),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemInstanceOrigin),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemLocation),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemPriority),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemRecurrence),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemReminder),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILGROUPNAME(ItemReminder),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemAudibleReminder),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILGROUPNAME(ItemAudibleReminder),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemVisualReminder),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILGROUPNAME(ItemVisualReminder),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemEmailReminder),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILGROUPNAME(ItemEmailReminder),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemTimestamp),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(ItemType),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(JournalTimeRange),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(TodoProgress),
    Q_DECLARATIVE_ORGANIZER_ITEM_DETAILNAME(TodoTimeRange)
};

QDeclarativeOrganizerItemMetaObject::QDeclarativeOrganizerItemMetaObject(QObject* obj, const QOrganizerItem& item)
    :QDeclarativeOpenMetaObject(obj)
{
    setItem(item);
}

QDeclarativeOrganizerItemMetaObject::~QDeclarativeOrganizerItemMetaObject()
{

}

void QDeclarativeOrganizerItemMetaObject::getValue(int propId, void **a)
{
    qDebug() << "value for propId:" << propId;
    OrganizerItemDetailNameMap* detailMetaData = m_properties.value(propId);
    if (detailMetaData) {
        if (detailMetaData->group) {
            qDebug() << "name:" << detailMetaData->name;
            *reinterpret_cast< QDeclarativeListProperty<QDeclarativeOrganizerItemDetail>* >(a[0]) =
                    QDeclarativeListProperty<QDeclarativeOrganizerItemDetail>(object(), detailMetaData, detail_append, detail_count, detail_at, detail_clear);

        } else {
            foreach(QDeclarativeOrganizerItemDetail* cd, m_details) {
                if (cd->detail().definitionName() == detailMetaData->definitionName) {
                    *reinterpret_cast<QVariant *>(a[0]) = QVariant::fromValue(cd);
                }
            }
        }
    }

}

void QDeclarativeOrganizerItemMetaObject::setValue(int propId, void **a)
{
    OrganizerItemDetailNameMap* detailMetaData = m_properties.value(propId);
    if (detailMetaData) {
        if (!detailMetaData->group) {
            QVariant& v = *reinterpret_cast<QVariant *>(a[0]);
            QDeclarativeOrganizerItemDetail* detail = v.value<QDeclarativeOrganizerItemDetail*>();

            foreach(QDeclarativeOrganizerItemDetail* cd, m_details) {
                if (cd->detail().definitionName() == detailMetaData->definitionName) {
                    delete cd;
                    cd = detail;
                }
            }
        }
    }
}

int QDeclarativeOrganizerItemMetaObject::createProperty(const char * name,  const char *)
{

    const int detailCount = sizeof(qt_organizerItemDetailNameMap)/sizeof(OrganizerItemDetailNameMap);
    OrganizerItemDetailNameMap* detailMetaData = 0;

    for (int i = 0; i < detailCount; i++) {
        if (QString::fromLocal8Bit(qt_organizerItemDetailNameMap[i].name) == QString::fromLocal8Bit(name)) {
            detailMetaData = &qt_organizerItemDetailNameMap[i];
            break;
        }
    }

    if (detailMetaData) {
        int propId = -1;
        if (detailMetaData->group)
            propId = QDeclarativeOpenMetaObject::createProperty(name, "QDeclarativeListProperty<QDeclarativeOrganizerItemDetail>");
        else
            propId = QDeclarativeOpenMetaObject::createProperty(name, "QVariant");
        m_properties.insert(propId, detailMetaData);
        qDebug() << "createProperty:" << name << "propId:" << propId;
        return propId;
    }
    return -1;
}

QVariant QDeclarativeOrganizerItemMetaObject::detail(const QString& name)
{
    int propId = indexOfProperty(name.toLatin1());

    if (propId > 0)
        return property(propId).read(object());

    //Assume it's a detail definition name
    foreach(QDeclarativeOrganizerItemDetail* cd, m_details) {
        if (cd->detail().definitionName() == name) {
            return QVariant::fromValue(cd);
        }
    }
    return QVariant();
}

QVariant QDeclarativeOrganizerItemMetaObject::details(const QString& name)
{
    if (name.isEmpty()) {
        //return all
        return QVariant::fromValue(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail>(object(), m_details));
    } else {
        int propId = indexOfProperty(name.toLatin1());
        if (propId > 0)
            return property(propId).read(object());

        //Assume it's a detail definition name
        //TODO::customized details
        for (QHash<int, OrganizerItemDetailNameMap*>::ConstIterator iter = m_properties.constBegin(); iter != m_properties.constEnd(); iter++) {
            if (iter.value()->group && iter.value()->definitionName == name)
                return property(iter.key()).read(object());
        }
    }
    return QVariant();
}

void QDeclarativeOrganizerItemMetaObject::setItem(const QOrganizerItem& contact)
{
    m_item = contact;
    QList<QOrganizerItemDetail> details = m_item.details();
    m_details.clear();
    foreach (const QOrganizerItemDetail& detail, details) {
      QDeclarativeOrganizerItemDetail* cd = new QDeclarativeOrganizerItemDetail(object());

      cd->connect(cd, SIGNAL(fieldsChanged()), object(), SIGNAL(detailsChanged()));

      cd->setDetail(detail);
      m_details.append(cd);
    }
}

QOrganizerItem QDeclarativeOrganizerItemMetaObject::item()
{
    m_item.clearDetails();
    foreach ( QDeclarativeOrganizerItemDetail* cd, m_details) {
       QOrganizerItemDetail detail = cd->detail();
       m_item.saveDetail(&detail);
    }
    return m_item;
}

uint QDeclarativeOrganizerItemMetaObject::localId() const
{
    return qHash(m_item.localId());
}

uint QDeclarativeOrganizerItemMetaObject::itemId() const
{
    return qHash(m_item.id());
}

void QDeclarativeOrganizerItemMetaObject::detail_append(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail> *p, QDeclarativeOrganizerItemDetail *detail)
{
    OrganizerItemDetailNameMap* data = (OrganizerItemDetailNameMap*)(p->data);
    if (data) {
        QDeclarativeOrganizerItem* dc = qobject_cast<QDeclarativeOrganizerItem*>(p->object);
        if (dc && detail->detail().definitionName() == data->definitionName) {
            detail->connect(detail, SIGNAL(fieldsChanged()), dc, SIGNAL(detailsChanged()));
            dc->d->m_details.append(detail);
        }
    }
}

int  QDeclarativeOrganizerItemMetaObject::detail_count(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail> *p)
{
    OrganizerItemDetailNameMap* data = (OrganizerItemDetailNameMap*)(p->data);
    int count = 0;
    QDeclarativeOrganizerItem* dc = qobject_cast<QDeclarativeOrganizerItem*>(p->object);
    if (dc && data) {
        foreach(QDeclarativeOrganizerItemDetail* detail, dc->d->m_details) {
            if (detail->detail().definitionName() == data->definitionName)
                count++;
        }
    }
    return count;
}

QDeclarativeOrganizerItemDetail * QDeclarativeOrganizerItemMetaObject::detail_at(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail> *p, int idx)
{
    OrganizerItemDetailNameMap* data = (OrganizerItemDetailNameMap*)(p->data);
    QDeclarativeOrganizerItemDetail* detail = 0;
    QDeclarativeOrganizerItem* dc = qobject_cast<QDeclarativeOrganizerItem*>(p->object);
    if (dc && data) {
        int i = 0;
        foreach(QDeclarativeOrganizerItemDetail* cd,dc->d->m_details) {
            if (cd->detail().definitionName() == data->definitionName) {
                if (i == idx) {
                    detail = cd;
                    break;
                } else {
                    i++;
                }
            }
        }
    }
    return detail;
}

void  QDeclarativeOrganizerItemMetaObject::detail_clear(QDeclarativeListProperty<QDeclarativeOrganizerItemDetail> *p)
{
    OrganizerItemDetailNameMap* data = (OrganizerItemDetailNameMap*)(p->data);
    QDeclarativeOrganizerItem* dc = qobject_cast<QDeclarativeOrganizerItem*>(p->object);
    if (dc && data) {
        foreach(QDeclarativeOrganizerItemDetail* cd, dc->d->m_details) {
            if (cd->detail().definitionName() == data->definitionName) {
                dc->d->m_details.removeAll(cd);
            }
        }
    }
}
<|endoftext|>