<commit_before>#include <queue>
#include <vector>
#include <string>
#include <cstring>
#include <iostream>
#include <fstream>
#include <time.h>
//#include <malloc.h>

using namespace std;

#define DEBUG       0

#define MAX_T       100
#define MAX_2       801
#define MAX_S       100001

int count[MAX_T];

int len_two[MAX_2];
vector<string> str_two(MAX_2);

void init() {
    for (size_t i = 0; i < MAX_2; i++) {
        if (0 == i) {
            str_two[i] = '1';
        }
        else {
            int carry = 0;
            int val = 0;
            for (size_t j = 0; j < str_two[i - 1].length(); j++) {
                val = (str_two[i - 1][j] - '0') * 2 + carry;
                if (9 < val) {
                    str_two[i] += '0' + val - 10;
                    carry = 1;
                }
                else {
                    str_two[i] += '0' + val;
                    carry = 0;
                }
            }

            if (0 < carry) {
                str_two[i] += '1';
            }
        }
    }
}

int two_two(string& s) {
    int ret = 0;

    return ret;
}

int main() {
    int t;

#if DEBUG
    ifstream fin("input.txt");
    if (!fin.is_open()) {
        printf("open file error!\n");
        return -1;
    }
    fin >> t;
#else
    cin >> t;
#endif

    init();

    string s;
    for (size_t i = 0; i < t; i++) {
#if DEBUG
        fin >> s;
#else
        cin >> s;
#endif
        count[i] = two_two(s);
    }

    for (size_t i = 0; i < t; i++) {
        cout << count[i];
    }

    return 0;
}
<commit_msg>150.00 points<commit_after>#include <queue>
#include <vector>
#include <string>
#include <cstring>
#include <iostream>
#include <fstream>
#include <time.h>
#include <algorithm>

using namespace std;

#define DEBUG       0

#define MAX_T       100
#define MAX_2       801
#define MAX_S       100001

int cnt[MAX_T];

// Max number of states in the matching machine.
// Should be equal to the sum of the length of all keywords.
//const int MAXS = 2000000;
int maxs;

vector<string> str_two(MAX_2);

// Maximum number of characters in input alphabet
const int MAXC = 10;

const int MAXM = 512;
const int ONE_MB = 1000000;

struct output {
    int value;
    struct output * next;
};

// OUTPUT FUNCTION IS IMPLEMENTED USING out[]
// Bit i in this mask is one if the word with index i
// appears when the machine enters this state.
//vector<int> out[MAXS];
struct output * * out;
struct output * * last;
struct output * mem[MAXM];

// FAILURE FUNCTION IS IMPLEMENTED USING f[]
int * f;

// GOTO FUNCTION (OR TRIE) IS IMPLEMENTED USING g[][]
//int g[MAXS][MAXC];
int * * g;

int index_in_mem = 0;
int index_in_1mb = 0;

struct output * getOneOutput() {
    struct output * ret = NULL;

    if (ONE_MB == index_in_1mb) {
        index_in_mem ++;
    }

    if (MAXM > index_in_mem)  {
        if (NULL == mem[index_in_mem]) {
            mem[index_in_mem] = (struct output *)malloc(ONE_MB * sizeof(struct output));
            index_in_1mb = 0;
        }

        ret = &mem[index_in_mem][index_in_1mb];
        ret->value = 0;
        ret->next = 0;
        index_in_1mb ++;
    }

    return ret;
}

//void addToOutput(struct output * * l, int value) {
void addToOutput(int index, int value) {
	struct output * tmp = getOneOutput();
	tmp->value = value;
	if (NULL == out[index]) {
		out[index] = tmp;
	}
	else {
		last[index]->next = tmp;
	}
	last[index] = tmp;
}

void mergeOutput(struct output * * l_a, struct output * * l_b) {
    if (*l_b) {
        struct output * p_a = * l_a;
        struct output * pp_a = NULL;
        struct output * p_b = * l_b;

        if (NULL == (*l_a)) {
            *l_a = getOneOutput();
            (*l_a)->value = p_b->value;

            p_a = *l_a;
            p_b = p_b->next;
        }

        while (p_a && p_b) {
            if (p_b->value == p_a->value) {
                p_a = p_a->next;
                p_b = p_b->next;
                if (pp_a) {
                    pp_a = pp_a->next;
                }
                else {
                    pp_a = *l_a;
                }
            }
            else if (p_b->value < p_a->value) {
                struct output * tmp = getOneOutput();
                tmp->value = p_b->value;
                tmp->next = p_a;

                if (pp_a) {
                    pp_a->next = tmp;
                }
                else {
                    * l_a = tmp;
                }
                pp_a = tmp;
                p_b = p_b->next;
            }
            else {
                p_a = p_a->next;
                if (pp_a) {
                    pp_a = pp_a->next;
                }
                else {
                    pp_a = *l_a;
                }

            }
        }

        while (p_b){
            struct output * tmp = getOneOutput();
            tmp->value = p_b->value;

            pp_a->next = tmp;
            pp_a = tmp;

            p_b = p_b->next;
        }
    }
}

// Builds the string matching machine.
// arr -   array of words. The index of each keyword is important:
//         "out[state] & (1 << i)" is > 0 if we just found word[i]
//         in the text.
// Returns the number of states that the built machine has.
// States are numbered 0 up to the return value - 1, inclusive.
int buildMatchingMachine(vector<string>& arr, int k)
{
    // Initialize all values in output function as 0.
    //    memset(out, 0, sizeof out);

    // Initially, we just have the 0 state
    int states = 1;

    // Construct values for goto function, i.e., fill g[][]
    // This is same as building a Trie for arr[]
    for (int i = 0; i < k; ++i)
    {
        const string &word = arr[i];
        int currentState = 0;

        // Insert all characters of current word in arr[]
        for (int j = 0; j < word.size(); ++j)
        {
            int ch = word[j] - '0';

            // Allocate a new node (create a new state) if a
            // node for ch doesn't exist.
            if (g[currentState][ch] == -1)
            g[currentState][ch] = states++;

            currentState = g[currentState][ch];
        }

        // Add current word in output function
        //        out[currentState] |= (1 << i);
//        addToOutput(&out[currentState], i);
        addToOutput(currentState, i);
    }

    // For all characters which don't have an edge from
    // root (or state 0) in Trie, add a goto edge to state
    // 0 itself
    for (int ch = 0; ch < MAXC; ++ch)
    if (g[0][ch] == -1)
    g[0][ch] = 0;

    // Now, let's build the failure function

    // Failure function is computed in breadth first order
    // using a queue
    queue<int> q;

    // Iterate over every possible input
    for (int ch = 0; ch < MAXC; ++ch)
    {
        // All nodes of depth 1 have failure function value
        // as 0. For example, in above diagram we move to 0
        // from states 1 and 3.
        if (g[0][ch] != 0)
        {
            f[g[0][ch]] = 0;
            q.push(g[0][ch]);
        }
    }

    // Now queue has states 1 and 3
    while (q.size())
    {
        // Remove the front state from queue
        int state = q.front();
        q.pop();

        // For the removed state, find failure function for
        // all those characters for which goto function is
        // not defined.
        for (int ch = 0; ch < MAXC; ++ch)
        {
            // If goto function is defined for character 'ch'
            // and 'state'
            if (g[state][ch] != -1)
            {
                // Find failure state of removed state
                int failure = f[state];

                // Find the deepest node labeled by proper
                // suffix of string from root to current
                // state.
                while (g[failure][ch] == -1)
                failure = f[failure];

                failure = g[failure][ch];
                f[g[state][ch]] = failure;

                // Merge output values
                mergeOutput(&out[g[state][ch]], &out[failure]);
                //                out[g[state][ch]] |= out[failure];

                // Insert the next level node (of Trie) in Queue
                q.push(g[state][ch]);
            }
        }
    }

    return states;
}

// Returns the next state the machine will transition to using goto
// and failure functions.
// currentState - The current state of the machine. Must be between
//                0 and the Nnumber of states - 1, inclusive.
// nextInput - The next character that enters into the machine.
int findNextState(int currentState, char nextInput)
{
    int answer = currentState;
    int ch = nextInput - '0';

    // If goto is not defined, use failure function
    while (g[answer][ch] == -1)
    answer = f[answer];

    return g[answer][ch];
}

void init() {
    for (size_t i = 0; i < MAX_2; i++) {
        if (0 == i) {
            str_two[i] = '1';
        }
        else {
            int carry = 0;
            int val = 0;
            for (size_t j = 0; j < str_two[i - 1].length(); j++) {
                val = (str_two[i - 1][j] - '0') * 2 + carry;
                if (9 < val) {
                    str_two[i] += '0' + val - 10;
                    carry = 1;
                }
                else {
                    str_two[i] += '0' + val;
                    carry = 0;
                }
            }

            if (0 < carry) {
                str_two[i] += '1';
            }
        }
        maxs += str_two[i].length();
    }

    // buildMatchingMachine
    f = (int *)malloc(maxs * sizeof(int));
    memset(f, -1, sizeof(maxs * sizeof(int)));

    g = (int * *)malloc(maxs * sizeof(int *));
    for (size_t i = 0; i < maxs; i++) {
        g[i] = (int *)malloc(MAXC * sizeof(int));
        memset(g[i], -1, MAXC * sizeof(int));
    }

    out = (struct output * *)malloc(maxs * sizeof(struct output *));
    memset(out, 0 , maxs * sizeof(struct output *));

    last = (struct output * *)malloc(maxs * sizeof(struct output *));
    memset(last, 0 , maxs * sizeof(struct output *));

    buildMatchingMachine(str_two, MAX_2);
}

int two_two(string& s) {
    int ret = 0;

    // reverse
    reverse(s.begin(), s.end());

    // Initialize current state
    int currentState = 0;

    // Traverse the text through the nuilt machine to find
    // all occurrences of words in arr[]
    for (int i = 0; i < s.size(); ++i)
	{
		currentState = findNextState(currentState, s[i]);

		// Match found, print all matching words of arr[]
		// using output function.
		struct output * p = out[currentState];

		while (p) {
			ret ++;
			p = p->next;
		}
	}

    return ret;
}

int main() {
    int t;

#if DEBUG
    ifstream fin("input.txt");
    if (!fin.is_open()) {
        printf("open file error!\n");
        return -1;
    }
    fin >> t;
#else
    cin >> t;
#endif

    init();

    string s;
    for (size_t i = 0; i < t; i++) {
#if DEBUG
        fin >> s;
#else
        cin >> s;
#endif
        cnt[i] = two_two(s);
    }

    for (size_t i = 0; i < t; i++) {
        cout << cnt[i] << "\n";
    }

    return 0;
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __WINDOWS__
#include <fts.h>
#endif // __WINDOWS__

#include <mesos/type_utils.hpp>

#include <mesos/docker/spec.hpp>

#include <process/collect.hpp>
#include <process/defer.hpp>
#include <process/dispatch.hpp>
#include <process/process.hpp>

#include <stout/foreach.hpp>
#include <stout/hashmap.hpp>
#include <stout/hashset.hpp>
#include <stout/os.hpp>
#include <stout/stringify.hpp>
#include <stout/uuid.hpp>

#include "slave/paths.hpp"

#include "slave/containerizer/mesos/provisioner/backend.hpp"
#include "slave/containerizer/mesos/provisioner/paths.hpp"
#include "slave/containerizer/mesos/provisioner/provisioner.hpp"
#include "slave/containerizer/mesos/provisioner/store.hpp"

using namespace process;

namespace spec = docker::spec;

using std::list;
using std::string;
using std::vector;

using mesos::slave::ContainerState;

namespace mesos {
namespace internal {
namespace slave {

Try<Owned<Provisioner>> Provisioner::create(const Flags& flags)
{
  string _rootDir = slave::paths::getProvisionerDir(flags.work_dir);

  Try<Nothing> mkdir = os::mkdir(_rootDir);
  if (mkdir.isError()) {
    return Error(
        "Failed to create provisioner root directory '" +
        _rootDir + "': " + mkdir.error());
  }

  Result<string> rootDir = os::realpath(_rootDir);
  if (rootDir.isError()) {
    return Error(
        "Failed to resolve the realpath of provisioner root directory '" +
        _rootDir + "': " + rootDir.error());
  }

  CHECK_SOME(rootDir); // Can't be None since we just created it.

  Try<hashmap<Image::Type, Owned<Store>>> stores = Store::create(flags);
  if (stores.isError()) {
    return Error("Failed to create image stores: " + stores.error());
  }

  hashmap<string, Owned<Backend>> backends = Backend::create(flags);
  if (backends.empty()) {
    return Error("No usable provisioner backend created");
  }

  if (!backends.contains(flags.image_provisioner_backend)) {
    return Error(
        "The specified provisioner backend '" +
        flags.image_provisioner_backend + "' is unsupported");
  }

  return Owned<Provisioner>(new Provisioner(
      Owned<ProvisionerProcess>(new ProvisionerProcess(
          flags,
          rootDir.get(),
          stores.get(),
          backends))));
}

Provisioner::Provisioner(Owned<ProvisionerProcess> _process)
  : process(_process)
{
  spawn(CHECK_NOTNULL(process.get()));
}

Provisioner::~Provisioner()
{
  if (process.get() != nullptr) {
    terminate(process.get());
    wait(process.get());
  }
}

Future<Nothing> Provisioner::recover(
    const list<ContainerState>& states,
    const hashset<ContainerID>& orphans)
{
  return dispatch(
      CHECK_NOTNULL(process.get()),
      &ProvisionerProcess::recover,
      states,
      orphans);
}

Future<ProvisionInfo> Provisioner::provision(
    const ContainerID& containerId,
    const Image& image)
{
  return dispatch(
      CHECK_NOTNULL(process.get()),
      &ProvisionerProcess::provision,
      containerId,
      image);
}

Future<bool> Provisioner::destroy(const ContainerID& containerId)
{
  return dispatch(
      CHECK_NOTNULL(process.get()),
      &ProvisionerProcess::destroy,
      containerId);
}

ProvisionerProcess::ProvisionerProcess(
    const Flags& _flags,
    const string& _rootDir,
    const hashmap<Image::Type, Owned<Store>>& _stores,
    const hashmap<string, Owned<Backend>>& _backends)
  : flags(_flags),
    rootDir(_rootDir),
    stores(_stores),
    backends(_backends) {}

Future<Nothing> ProvisionerProcess::recover(
    const list<ContainerState>& states,
    const hashset<ContainerID>& orphans)
{
  // Register living containers, including the ones that do not
  // provision images.
  hashset<ContainerID> alive;
  foreach (const ContainerState& state, states) {
    alive.insert(state.container_id());
  }

  // List provisioned containers; recover living ones; destroy unknown
  // orphans. Note that known orphan containers are recovered as well
  // and they will be destroyed by the containerizer using the normal
  // cleanup path. See MESOS-2367 for details.
  Try<hashset<ContainerID>> containers =
    provisioner::paths::listContainers(rootDir);

  if (containers.isError()) {
    return Failure(
        "Failed to list the containers managed by the provisioner: " +
        containers.error());
  }

  // Scan the list of containers, register all of them with 'infos'
  // but mark unknown orphans for immediate cleanup.
  hashset<ContainerID> unknownOrphans;

  foreach (const ContainerID& containerId, containers.get()) {
    Owned<Info> info = Owned<Info>(new Info());

    Try<hashmap<string, hashset<string>>> rootfses =
      provisioner::paths::listContainerRootfses(rootDir, containerId);

    if (rootfses.isError()) {
      return Failure(
          "Unable to list rootfses belonged to container " +
          stringify(containerId) + ": " + rootfses.error());
    }

    foreachkey (const string& backend, rootfses.get()) {
      if (!backends.contains(backend)) {
        return Failure(
            "Found rootfses managed by an unrecognized backend: " + backend);
      }

      info->rootfses.put(backend, rootfses.get()[backend]);
    }

    infos.put(containerId, info);

    if (alive.contains(containerId) || orphans.contains(containerId)) {
      LOG(INFO) << "Recovered container " << containerId;
      continue;
    } else {
      // For immediate cleanup below.
      unknownOrphans.insert(containerId);
    }
  }

  // Cleanup unknown orphan containers' rootfses.
  list<Future<bool>> cleanups;
  foreach (const ContainerID& containerId, unknownOrphans) {
    LOG(INFO) << "Cleaning up unknown orphan container " << containerId;
    cleanups.push_back(destroy(containerId));
  }

  Future<Nothing> cleanup = collect(cleanups)
    .then([]() -> Future<Nothing> { return Nothing(); });

  // Recover stores.
  list<Future<Nothing>> recovers;
  foreachvalue (const Owned<Store>& store, stores) {
    recovers.push_back(store->recover());
  }

  Future<Nothing> recover = collect(recovers)
    .then([]() -> Future<Nothing> { return Nothing(); });

  // A successful provisioner recovery depends on:
  // 1) Recovery of living containers and known orphans (done above).
  // 2) Successful cleanup of unknown orphans.
  // 3) Successful store recovery.
  //
  // TODO(jieyu): Do not recover 'store' before unknown orphans are
  // cleaned up. In the future, we may want to cleanup unused rootfses
  // in 'store', which might fail if there still exist unknown orphans
  // holding references to them.
  return collect(cleanup, recover)
    .then([=]() -> Future<Nothing> {
      LOG(INFO) << "Provisioner recovery complete";
      return Nothing();
    });
}

Future<ProvisionInfo> ProvisionerProcess::provision(
    const ContainerID& containerId,
    const Image& image)
{
  if (!stores.contains(image.type())) {
    return Failure(
        "Unsupported container image type: " +
        stringify(image.type()));
  }

  // Get and then provision image layers from the store.
  return stores.get(image.type()).get()->get(image)
    .then(defer(self(), &Self::_provision, containerId, image, lambda::_1));
}

Future<ProvisionInfo> ProvisionerProcess::_provision(
    const ContainerID& containerId,
    const Image& image,
    const ImageInfo& imageInfo)
{
  // TODO(jieyu): Choose a backend smartly. For instance, if there is
  // only one layer returned from the store. prefer to use bind
  // backend because it's the simplest.
  const string& backend = flags.image_provisioner_backend;
  CHECK(backends.contains(backend));

  string rootfsId = UUID::random().toString();

  string rootfs = provisioner::paths::getContainerRootfsDir(
      rootDir,
      containerId,
      backend,
      rootfsId);

  LOG(INFO) << "Provisioning image rootfs '" << rootfs
            << "' for container " << containerId;

  // NOTE: It's likely that the container ID already exists in 'infos'
  // because one container might provision multiple images.
  if (!infos.contains(containerId)) {
    infos.put(containerId, Owned<Info>(new Info()));
  }

  infos[containerId]->rootfses[backend].insert(rootfsId);

  string backendDir = provisioner::paths::getBackendDir(
      rootDir,
      containerId,
      backend);

  return backends.get(backend).get()->provision(
      imageInfo.layers,
      rootfs,
      backendDir)
    .then(defer(self(), &Self::__provision, rootfs, image, imageInfo));
}

// This function is currently docker image specific. Depending
// on docker v1 spec, a docker image may include filesystem
// changeset, which may need to delete directories or files.
// The file/dir to be deleted will be labeled by creating a
// 'whiteout' file, which is at the same location and with the
// basename of the deleted file or directory prefixed with
// '.wh.'. Please see:
// https://github.com/docker/docker/blob/master/image/spec/v1.md
Future<ProvisionInfo> ProvisionerProcess::__provision(
    const string& rootfs,
    const Image& image,
    const ImageInfo& imageInfo)
{
  // Skip single-layered images since no 'whiteout' files needs
  // to be handled, and this excludes any image using the bind
  // backend.
  if (imageInfo.layers.size() == 1 || image.type() != Image::DOCKER) {
    return ProvisionInfo{rootfs, imageInfo.dockerManifest};
  }

#ifndef __WINDOWS__
  char* _rootfs[] = {const_cast<char*>(rootfs.c_str()), nullptr};

  FTS* tree = ::fts_open(_rootfs, FTS_NOCHDIR | FTS_PHYSICAL, nullptr);
  if (tree == nullptr) {
    return Failure("Failed to open '" + rootfs + "': " + os::strerror(errno));
  }

  vector<string> whiteout;

  for (FTSENT *node = ::fts_read(tree);
       node != nullptr; node = ::fts_read(tree)) {
    if (node->fts_info == FTS_F &&
        strings::startsWith(node->fts_name, string(spec::WHITEOUT_PREFIX))) {
      Path path = Path(node->fts_path);

      whiteout.push_back(path::join(path.dirname(), path.basename().substr(
          strlen(spec::WHITEOUT_PREFIX))));

      Try<Nothing> rm = os::rm(path.value);
      if (rm.isError()) {
        ::fts_close(tree);
        return Failure(
            "Failed to remove the whiteout '.wh.' file '" +
            path.value + "': " + rm.error());
      }
    }
  }

  if (errno != 0) {
    Error error = ErrnoError();
    ::fts_close(tree);
    return Failure(error);
  }

  if (::fts_close(tree) != 0) {
    return Failure(
        "Failed to stop traversing file system: " + os::strerror(errno));
  }

  foreach (const string& path, whiteout) {
    if (os::stat::isdir(path)) {
      Try<Nothing> rmdir = os::rmdir(path);
      if (rmdir.isError()) {
        return Failure(
            "Failed to remove whiteout directory '" +
            path + "': " + rmdir.error());
      }
    } else {
      Try<Nothing> rm = os::rm(path);
      if (rm.isError()) {
        return Failure(
            "Failed to remove whiteout file '" +
            path + "': " + rm.error());
      }
    }
  }

  return ProvisionInfo{rootfs, imageInfo.dockerManifest};
#else
  return ProvisionInfo{ rootfs, imageInfo.dockerManifest };
#endif // __WINDOWS__
}

Future<bool> ProvisionerProcess::destroy(const ContainerID& containerId)
{
  if (!infos.contains(containerId)) {
    VLOG(1) << "Ignoring destroy request for unknown container " << containerId;

    return false;
  }

  // Unregister the container first. If destroy() fails, we can rely
  // on recover() to retry it later.
  Owned<Info> info = infos[containerId];
  infos.erase(containerId);

  list<Future<bool>> futures;
  foreachkey (const string& backend, info->rootfses) {
    if (!backends.contains(backend)) {
      return Failure("Unknown backend '" + backend + "'");
    }

    foreach (const string& rootfsId, info->rootfses[backend]) {
      string rootfs = provisioner::paths::getContainerRootfsDir(
          rootDir,
          containerId,
          backend,
          rootfsId);

      LOG(INFO) << "Destroying container rootfs at '" << rootfs
                << "' for container " << containerId;

      futures.push_back(backends.get(backend).get()->destroy(rootfs));
    }
  }

  // TODO(xujyan): Revisit the usefulness of this return value.
  return collect(futures)
    .then(defer(self(), &ProvisionerProcess::_destroy, containerId));
}

Future<bool> ProvisionerProcess::_destroy(const ContainerID& containerId)
{
  // This should be fairly cheap as the directory should only
  // contain a few empty sub-directories at this point.
  //
  // TODO(jieyu): Currently, it's possible that some directories
  // cannot be removed due to EBUSY. EBUSY is caused by the race
  // between cleaning up this container and new containers copying
  // the host mount table. It's OK to ignore them. The cleanup
  // will be retried during slave recovery.
  string containerDir =
    provisioner::paths::getContainerDir(rootDir, containerId);

  Try<Nothing> rmdir = os::rmdir(containerDir);
  if (rmdir.isError()) {
    LOG(ERROR) << "Failed to remove the provisioned container directory "
               << "at '" << containerDir << "': " << rmdir.error();

    ++metrics.remove_container_errors;
  }

  return true;
}

ProvisionerProcess::Metrics::Metrics()
  : remove_container_errors(
      "containerizer/mesos/provisioner/remove_container_errors")
{
  process::metrics::add(remove_container_errors);
}

ProvisionerProcess::Metrics::~Metrics()
{
  process::metrics::remove(remove_container_errors);
}

} // namespace slave {
} // namespace internal {
} // namespace mesos {
<commit_msg>Added TODO to support Docker 'whiteout' deletions on Windows.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __WINDOWS__
#include <fts.h>
#endif // __WINDOWS__

#include <mesos/type_utils.hpp>

#include <mesos/docker/spec.hpp>

#include <process/collect.hpp>
#include <process/defer.hpp>
#include <process/dispatch.hpp>
#include <process/process.hpp>

#include <stout/foreach.hpp>
#include <stout/hashmap.hpp>
#include <stout/hashset.hpp>
#include <stout/os.hpp>
#include <stout/stringify.hpp>
#include <stout/uuid.hpp>

#include "slave/paths.hpp"

#include "slave/containerizer/mesos/provisioner/backend.hpp"
#include "slave/containerizer/mesos/provisioner/paths.hpp"
#include "slave/containerizer/mesos/provisioner/provisioner.hpp"
#include "slave/containerizer/mesos/provisioner/store.hpp"

using namespace process;

namespace spec = docker::spec;

using std::list;
using std::string;
using std::vector;

using mesos::slave::ContainerState;

namespace mesos {
namespace internal {
namespace slave {

Try<Owned<Provisioner>> Provisioner::create(const Flags& flags)
{
  string _rootDir = slave::paths::getProvisionerDir(flags.work_dir);

  Try<Nothing> mkdir = os::mkdir(_rootDir);
  if (mkdir.isError()) {
    return Error(
        "Failed to create provisioner root directory '" +
        _rootDir + "': " + mkdir.error());
  }

  Result<string> rootDir = os::realpath(_rootDir);
  if (rootDir.isError()) {
    return Error(
        "Failed to resolve the realpath of provisioner root directory '" +
        _rootDir + "': " + rootDir.error());
  }

  CHECK_SOME(rootDir); // Can't be None since we just created it.

  Try<hashmap<Image::Type, Owned<Store>>> stores = Store::create(flags);
  if (stores.isError()) {
    return Error("Failed to create image stores: " + stores.error());
  }

  hashmap<string, Owned<Backend>> backends = Backend::create(flags);
  if (backends.empty()) {
    return Error("No usable provisioner backend created");
  }

  if (!backends.contains(flags.image_provisioner_backend)) {
    return Error(
        "The specified provisioner backend '" +
        flags.image_provisioner_backend + "' is unsupported");
  }

  return Owned<Provisioner>(new Provisioner(
      Owned<ProvisionerProcess>(new ProvisionerProcess(
          flags,
          rootDir.get(),
          stores.get(),
          backends))));
}

Provisioner::Provisioner(Owned<ProvisionerProcess> _process)
  : process(_process)
{
  spawn(CHECK_NOTNULL(process.get()));
}

Provisioner::~Provisioner()
{
  if (process.get() != nullptr) {
    terminate(process.get());
    wait(process.get());
  }
}

Future<Nothing> Provisioner::recover(
    const list<ContainerState>& states,
    const hashset<ContainerID>& orphans)
{
  return dispatch(
      CHECK_NOTNULL(process.get()),
      &ProvisionerProcess::recover,
      states,
      orphans);
}

Future<ProvisionInfo> Provisioner::provision(
    const ContainerID& containerId,
    const Image& image)
{
  return dispatch(
      CHECK_NOTNULL(process.get()),
      &ProvisionerProcess::provision,
      containerId,
      image);
}

Future<bool> Provisioner::destroy(const ContainerID& containerId)
{
  return dispatch(
      CHECK_NOTNULL(process.get()),
      &ProvisionerProcess::destroy,
      containerId);
}

ProvisionerProcess::ProvisionerProcess(
    const Flags& _flags,
    const string& _rootDir,
    const hashmap<Image::Type, Owned<Store>>& _stores,
    const hashmap<string, Owned<Backend>>& _backends)
  : flags(_flags),
    rootDir(_rootDir),
    stores(_stores),
    backends(_backends) {}

Future<Nothing> ProvisionerProcess::recover(
    const list<ContainerState>& states,
    const hashset<ContainerID>& orphans)
{
  // Register living containers, including the ones that do not
  // provision images.
  hashset<ContainerID> alive;
  foreach (const ContainerState& state, states) {
    alive.insert(state.container_id());
  }

  // List provisioned containers; recover living ones; destroy unknown
  // orphans. Note that known orphan containers are recovered as well
  // and they will be destroyed by the containerizer using the normal
  // cleanup path. See MESOS-2367 for details.
  Try<hashset<ContainerID>> containers =
    provisioner::paths::listContainers(rootDir);

  if (containers.isError()) {
    return Failure(
        "Failed to list the containers managed by the provisioner: " +
        containers.error());
  }

  // Scan the list of containers, register all of them with 'infos'
  // but mark unknown orphans for immediate cleanup.
  hashset<ContainerID> unknownOrphans;

  foreach (const ContainerID& containerId, containers.get()) {
    Owned<Info> info = Owned<Info>(new Info());

    Try<hashmap<string, hashset<string>>> rootfses =
      provisioner::paths::listContainerRootfses(rootDir, containerId);

    if (rootfses.isError()) {
      return Failure(
          "Unable to list rootfses belonged to container " +
          stringify(containerId) + ": " + rootfses.error());
    }

    foreachkey (const string& backend, rootfses.get()) {
      if (!backends.contains(backend)) {
        return Failure(
            "Found rootfses managed by an unrecognized backend: " + backend);
      }

      info->rootfses.put(backend, rootfses.get()[backend]);
    }

    infos.put(containerId, info);

    if (alive.contains(containerId) || orphans.contains(containerId)) {
      LOG(INFO) << "Recovered container " << containerId;
      continue;
    } else {
      // For immediate cleanup below.
      unknownOrphans.insert(containerId);
    }
  }

  // Cleanup unknown orphan containers' rootfses.
  list<Future<bool>> cleanups;
  foreach (const ContainerID& containerId, unknownOrphans) {
    LOG(INFO) << "Cleaning up unknown orphan container " << containerId;
    cleanups.push_back(destroy(containerId));
  }

  Future<Nothing> cleanup = collect(cleanups)
    .then([]() -> Future<Nothing> { return Nothing(); });

  // Recover stores.
  list<Future<Nothing>> recovers;
  foreachvalue (const Owned<Store>& store, stores) {
    recovers.push_back(store->recover());
  }

  Future<Nothing> recover = collect(recovers)
    .then([]() -> Future<Nothing> { return Nothing(); });

  // A successful provisioner recovery depends on:
  // 1) Recovery of living containers and known orphans (done above).
  // 2) Successful cleanup of unknown orphans.
  // 3) Successful store recovery.
  //
  // TODO(jieyu): Do not recover 'store' before unknown orphans are
  // cleaned up. In the future, we may want to cleanup unused rootfses
  // in 'store', which might fail if there still exist unknown orphans
  // holding references to them.
  return collect(cleanup, recover)
    .then([=]() -> Future<Nothing> {
      LOG(INFO) << "Provisioner recovery complete";
      return Nothing();
    });
}

Future<ProvisionInfo> ProvisionerProcess::provision(
    const ContainerID& containerId,
    const Image& image)
{
  if (!stores.contains(image.type())) {
    return Failure(
        "Unsupported container image type: " +
        stringify(image.type()));
  }

  // Get and then provision image layers from the store.
  return stores.get(image.type()).get()->get(image)
    .then(defer(self(), &Self::_provision, containerId, image, lambda::_1));
}

Future<ProvisionInfo> ProvisionerProcess::_provision(
    const ContainerID& containerId,
    const Image& image,
    const ImageInfo& imageInfo)
{
  // TODO(jieyu): Choose a backend smartly. For instance, if there is
  // only one layer returned from the store. prefer to use bind
  // backend because it's the simplest.
  const string& backend = flags.image_provisioner_backend;
  CHECK(backends.contains(backend));

  string rootfsId = UUID::random().toString();

  string rootfs = provisioner::paths::getContainerRootfsDir(
      rootDir,
      containerId,
      backend,
      rootfsId);

  LOG(INFO) << "Provisioning image rootfs '" << rootfs
            << "' for container " << containerId;

  // NOTE: It's likely that the container ID already exists in 'infos'
  // because one container might provision multiple images.
  if (!infos.contains(containerId)) {
    infos.put(containerId, Owned<Info>(new Info()));
  }

  infos[containerId]->rootfses[backend].insert(rootfsId);

  string backendDir = provisioner::paths::getBackendDir(
      rootDir,
      containerId,
      backend);

  return backends.get(backend).get()->provision(
      imageInfo.layers,
      rootfs,
      backendDir)
    .then(defer(self(), &Self::__provision, rootfs, image, imageInfo));
}

// This function is currently docker image specific. Depending
// on docker v1 spec, a docker image may include filesystem
// changeset, which may need to delete directories or files.
// The file/dir to be deleted will be labeled by creating a
// 'whiteout' file, which is at the same location and with the
// basename of the deleted file or directory prefixed with
// '.wh.'. Please see:
// https://github.com/docker/docker/blob/master/image/spec/v1.md
Future<ProvisionInfo> ProvisionerProcess::__provision(
    const string& rootfs,
    const Image& image,
    const ImageInfo& imageInfo)
{
  // Skip single-layered images since no 'whiteout' files needs
  // to be handled, and this excludes any image using the bind
  // backend.
  if (imageInfo.layers.size() == 1 || image.type() != Image::DOCKER) {
    return ProvisionInfo{rootfs, imageInfo.dockerManifest};
  }

#ifndef __WINDOWS__
  // TODO(hausdorff): The FTS API is not available on some platforms, such as
  // Windows. We will need to either (1) prove that this is not necessary for
  // Windows Containers, which use much of the Docker spec themselves, or (2)
  // make this code compatible with Windows, as we did with other code that
  // depended on FTS, such as `os::rmdir`. See MESOS-5610.
  char* _rootfs[] = {const_cast<char*>(rootfs.c_str()), nullptr};

  FTS* tree = ::fts_open(_rootfs, FTS_NOCHDIR | FTS_PHYSICAL, nullptr);
  if (tree == nullptr) {
    return Failure("Failed to open '" + rootfs + "': " + os::strerror(errno));
  }

  vector<string> whiteout;

  for (FTSENT *node = ::fts_read(tree);
       node != nullptr; node = ::fts_read(tree)) {
    if (node->fts_info == FTS_F &&
        strings::startsWith(node->fts_name, string(spec::WHITEOUT_PREFIX))) {
      Path path = Path(node->fts_path);

      whiteout.push_back(path::join(path.dirname(), path.basename().substr(
          strlen(spec::WHITEOUT_PREFIX))));

      Try<Nothing> rm = os::rm(path.value);
      if (rm.isError()) {
        ::fts_close(tree);
        return Failure(
            "Failed to remove the whiteout '.wh.' file '" +
            path.value + "': " + rm.error());
      }
    }
  }

  if (errno != 0) {
    Error error = ErrnoError();
    ::fts_close(tree);
    return Failure(error);
  }

  if (::fts_close(tree) != 0) {
    return Failure(
        "Failed to stop traversing file system: " + os::strerror(errno));
  }

  foreach (const string& path, whiteout) {
    if (os::stat::isdir(path)) {
      Try<Nothing> rmdir = os::rmdir(path);
      if (rmdir.isError()) {
        return Failure(
            "Failed to remove whiteout directory '" +
            path + "': " + rmdir.error());
      }
    } else {
      Try<Nothing> rm = os::rm(path);
      if (rm.isError()) {
        return Failure(
            "Failed to remove whiteout file '" +
            path + "': " + rm.error());
      }
    }
  }

  return ProvisionInfo{rootfs, imageInfo.dockerManifest};
#else
  return ProvisionInfo{ rootfs, imageInfo.dockerManifest };
#endif // __WINDOWS__
}

Future<bool> ProvisionerProcess::destroy(const ContainerID& containerId)
{
  if (!infos.contains(containerId)) {
    VLOG(1) << "Ignoring destroy request for unknown container " << containerId;

    return false;
  }

  // Unregister the container first. If destroy() fails, we can rely
  // on recover() to retry it later.
  Owned<Info> info = infos[containerId];
  infos.erase(containerId);

  list<Future<bool>> futures;
  foreachkey (const string& backend, info->rootfses) {
    if (!backends.contains(backend)) {
      return Failure("Unknown backend '" + backend + "'");
    }

    foreach (const string& rootfsId, info->rootfses[backend]) {
      string rootfs = provisioner::paths::getContainerRootfsDir(
          rootDir,
          containerId,
          backend,
          rootfsId);

      LOG(INFO) << "Destroying container rootfs at '" << rootfs
                << "' for container " << containerId;

      futures.push_back(backends.get(backend).get()->destroy(rootfs));
    }
  }

  // TODO(xujyan): Revisit the usefulness of this return value.
  return collect(futures)
    .then(defer(self(), &ProvisionerProcess::_destroy, containerId));
}

Future<bool> ProvisionerProcess::_destroy(const ContainerID& containerId)
{
  // This should be fairly cheap as the directory should only
  // contain a few empty sub-directories at this point.
  //
  // TODO(jieyu): Currently, it's possible that some directories
  // cannot be removed due to EBUSY. EBUSY is caused by the race
  // between cleaning up this container and new containers copying
  // the host mount table. It's OK to ignore them. The cleanup
  // will be retried during slave recovery.
  string containerDir =
    provisioner::paths::getContainerDir(rootDir, containerId);

  Try<Nothing> rmdir = os::rmdir(containerDir);
  if (rmdir.isError()) {
    LOG(ERROR) << "Failed to remove the provisioned container directory "
               << "at '" << containerDir << "': " << rmdir.error();

    ++metrics.remove_container_errors;
  }

  return true;
}

ProvisionerProcess::Metrics::Metrics()
  : remove_container_errors(
      "containerizer/mesos/provisioner/remove_container_errors")
{
  process::metrics::add(remove_container_errors);
}

ProvisionerProcess::Metrics::~Metrics()
{
  process::metrics::remove(remove_container_errors);
}

} // namespace slave {
} // namespace internal {
} // namespace mesos {
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/celltypes.h"
#include "kernel/log.h"
#include "kernel/register.h"
#include "kernel/rtlil.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SynthIntelPass : public ScriptPass {
	SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {}

	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    synth_intel [options]\n");
		log("\n");
		log("This command runs synthesis for Intel FPGAs.\n");
		log("\n");
		log("    -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
		log("        generate the synthesis netlist for the specified family.\n");
		log("        MAX10 is the default target if not family argument specified.\n");
		log("        For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
		log("        Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
		log("\n");
		log("    -top <module>\n");
		log("        use the specified module as top module (default='top')\n");
		log("\n");
		log("    -vqm <file>\n");
		log("        write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
		log("        output file is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -vpr <file>\n");
		log("        write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
		log("        compatible with the Quartus flow. Writing of an\n");
		log("        output file is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -run <from_label>:<to_label>\n");
		log("        only run the commands between the labels (see below). an empty\n");
		log("        from label is synonymous to 'begin', and empty to label is\n");
		log("        synonymous to the end of the command list.\n");
		log("\n");
		log("    -noiopads\n");
		log("        do not use altsyncram cells in output netlist\n");
		log("\n");
		log("    -nobram\n");
		log("        do not use altsyncram cells in output netlist\n");
		log("\n");
		log("    -noflatten\n");
		log("        do not flatten design before synthesis\n");
		log("\n");
		log("    -retime\n");
		log("        run 'abc' with -dff option\n");
		log("\n");
		log("The following commands are executed by this synthesis command:\n");
		help_script();
		log("\n");
	}

	string top_opt, family_opt, vout_file, blif_file;
	bool retime, flatten, nobram, noiopads;

	void clear_flags() YS_OVERRIDE
	{
		top_opt = "-auto-top";
		family_opt = "max10";
		vout_file = "";
		blif_file = "";
		retime = false;
		flatten = true;
		nobram = false;
		noiopads = false;
	}

	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		string run_from, run_to;
		clear_flags();

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-family" && argidx + 1 < args.size()) {
				family_opt = args[++argidx];
				continue;
			}
			if (args[argidx] == "-top" && argidx + 1 < args.size()) {
				top_opt = "-top " + args[++argidx];
				continue;
			}
			if (args[argidx] == "-vqm" && argidx + 1 < args.size()) {
				vout_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-vpr" && argidx + 1 < args.size()) {
				blif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-run" && argidx + 1 < args.size()) {
				size_t pos = args[argidx + 1].find(':');
				if (pos == std::string::npos)
					break;
				run_from = args[++argidx].substr(0, pos);
				run_to = args[argidx].substr(pos + 1);
				continue;
			}
			if (args[argidx] == "-noiopads") {
				noiopads = true;
				continue;
			}
			if (args[argidx] == "-nobram") {
				nobram = true;
				continue;
			}
			if (args[argidx] == "-noflatten") {
				flatten = false;
				continue;
			}
			if (args[argidx] == "-retime") {
				retime = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if (!design->full_selection())
			log_cmd_error("This command only operates on fully selected designs!\n");
		if (family_opt != "max10" && family_opt != "a10gx" && family_opt != "cyclonev" && family_opt != "cycloneiv" &&
		    family_opt != "cycloneive" && family_opt != "cyclone10")
			log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());

		log_header(design, "Executing SYNTH_INTEL pass.\n");
		log_push();

		run_script(design, run_from, run_to);

		log_pop();
	}

	void script() YS_OVERRIDE
	{
		if (check_label("begin")) {
			if (check_label("family") && family_opt == "max10")
				run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
			else if (check_label("family") && family_opt == "a10gx")
				run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
			else if (check_label("family") && family_opt == "cyclonev")
				run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
			else if (check_label("family") && family_opt == "cyclone10")
				run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
			else if (check_label("family") && family_opt == "cycloneiv")
				run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
			else
				run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
			// Misc and common cells
			run("read_verilog -sv -lib +/intel/common/m9k_bb.v");
			run("read_verilog -sv -lib +/intel/common/altpll_bb.v");
			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
		}

		if (flatten && check_label("flatten", "(unless -noflatten)")) {
			run("proc");
			run("flatten");
			run("tribuf -logic");
			run("deminout");
		}

		if (check_label("coarse")) {
			run("synth -run coarse");
		}

		if (!nobram && check_label("bram", "(skip if -nobram)")) {
			run("memory_bram -rules +/intel/common/brams.txt");
			run("techmap -map +/intel/common/brams_map.v");
		}

		if (check_label("fine")) {
			run("opt -fast -mux_undef -undriven -fine -full");
			run("memory_map");
			run("opt -undriven -fine");
			run("dffsr2dff");
			run("dff2dffe -direct-match $_DFF_*");
			run("opt -fine");
			run("techmap -map +/techmap.v");
			run("opt -full");
			run("clean -purge");
			run("setundef -undriven -zero");
			if (retime || help_mode)
				run("abc -markgroups -dff", "(only if -retime)");
		}

		if (check_label("map_luts")) {
			if (family_opt == "a10gx" || family_opt == "cyclonev")
				run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
			else
				run("abc -lut 4" + string(retime ? " -dff" : ""));
			run("clean");
		}

		if (check_label("map_cells")) {
			if (!noiopads)
				run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
			if (family_opt == "max10")
				run("techmap -map +/intel/max10/cells_map.v");
			else if (family_opt == "a10gx")
				run("techmap -map +/intel/a10gx/cells_map.v");
			else if (family_opt == "cyclonev")
				run("techmap -map +/intel/cyclonev/cells_map.v");
			else if (family_opt == "cyclone10")
				run("techmap -map +/intel/cyclone10/cells_map.v");
			else if (family_opt == "cycloneiv")
				run("techmap -map +/intel/cycloneiv/cells_map.v");
			else
				run("techmap -map +/intel/cycloneive/cells_map.v");
			run("dffinit -highlow -ff dffeas q power_up");
			run("clean -purge");
		}

		if (check_label("check")) {
			run("hierarchy -check");
			run("stat");
			run("check -noinit");
		}

		if (check_label("vqm")) {
			if (!vout_file.empty() || help_mode)
				run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
					    help_mode ? "<file-name>" : vout_file.c_str()));
		}

		if (check_label("vpr")) {
			if (!blif_file.empty() || help_mode) {
				run(stringf("opt_clean -purge"));
				run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
			}
		}
	}
} SynthIntelPass;

PRIVATE_NAMESPACE_END
<commit_msg>synth_intel: Warn about untested Quartus backend<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/celltypes.h"
#include "kernel/log.h"
#include "kernel/register.h"
#include "kernel/rtlil.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SynthIntelPass : public ScriptPass {
	SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {}

	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    synth_intel [options]\n");
		log("\n");
		log("This command runs synthesis for Intel FPGAs.\n");
		log("\n");
		log("    -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
		log("        generate the synthesis netlist for the specified family.\n");
		log("        MAX10 is the default target if not family argument specified.\n");
		log("        For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
		log("        Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
		log("\n");
		log("    -top <module>\n");
		log("        use the specified module as top module (default='top')\n");
		log("\n");
		log("    -vqm <file>\n");
		log("        write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
		log("        output file is omitted if this parameter is not specified.\n");
		log("        Note that this backend has not been tested and is likely incompatible\n");
		log("        with recent versions of Quartus.\n");
		log("\n");
		log("    -vpr <file>\n");
		log("        write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
		log("        compatible with the Quartus flow. Writing of an\n");
		log("        output file is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -run <from_label>:<to_label>\n");
		log("        only run the commands between the labels (see below). an empty\n");
		log("        from label is synonymous to 'begin', and empty to label is\n");
		log("        synonymous to the end of the command list.\n");
		log("\n");
		log("    -noiopads\n");
		log("        do not use altsyncram cells in output netlist\n");
		log("\n");
		log("    -nobram\n");
		log("        do not use altsyncram cells in output netlist\n");
		log("\n");
		log("    -noflatten\n");
		log("        do not flatten design before synthesis\n");
		log("\n");
		log("    -retime\n");
		log("        run 'abc' with -dff option\n");
		log("\n");
		log("The following commands are executed by this synthesis command:\n");
		help_script();
		log("\n");
	}

	string top_opt, family_opt, vout_file, blif_file;
	bool retime, flatten, nobram, noiopads;

	void clear_flags() YS_OVERRIDE
	{
		top_opt = "-auto-top";
		family_opt = "max10";
		vout_file = "";
		blif_file = "";
		retime = false;
		flatten = true;
		nobram = false;
		noiopads = false;
	}

	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		string run_from, run_to;
		clear_flags();

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-family" && argidx + 1 < args.size()) {
				family_opt = args[++argidx];
				continue;
			}
			if (args[argidx] == "-top" && argidx + 1 < args.size()) {
				top_opt = "-top " + args[++argidx];
				continue;
			}
			if (args[argidx] == "-vqm" && argidx + 1 < args.size()) {
				vout_file = args[++argidx];
				log_warning("The Quartus backend has not been tested recently and is likely incompatible with modern versions of Quartus.\n");
				continue;
			}
			if (args[argidx] == "-vpr" && argidx + 1 < args.size()) {
				blif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-run" && argidx + 1 < args.size()) {
				size_t pos = args[argidx + 1].find(':');
				if (pos == std::string::npos)
					break;
				run_from = args[++argidx].substr(0, pos);
				run_to = args[argidx].substr(pos + 1);
				continue;
			}
			if (args[argidx] == "-noiopads") {
				noiopads = true;
				continue;
			}
			if (args[argidx] == "-nobram") {
				nobram = true;
				continue;
			}
			if (args[argidx] == "-noflatten") {
				flatten = false;
				continue;
			}
			if (args[argidx] == "-retime") {
				retime = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if (!design->full_selection())
			log_cmd_error("This command only operates on fully selected designs!\n");
		if (family_opt != "max10" && family_opt != "a10gx" && family_opt != "cyclonev" && family_opt != "cycloneiv" &&
		    family_opt != "cycloneive" && family_opt != "cyclone10")
			log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());

		log_header(design, "Executing SYNTH_INTEL pass.\n");
		log_push();

		run_script(design, run_from, run_to);

		log_pop();
	}

	void script() YS_OVERRIDE
	{
		if (check_label("begin")) {
			if (check_label("family") && family_opt == "max10")
				run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
			else if (check_label("family") && family_opt == "a10gx")
				run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
			else if (check_label("family") && family_opt == "cyclonev")
				run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
			else if (check_label("family") && family_opt == "cyclone10")
				run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
			else if (check_label("family") && family_opt == "cycloneiv")
				run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
			else
				run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
			// Misc and common cells
			run("read_verilog -sv -lib +/intel/common/m9k_bb.v");
			run("read_verilog -sv -lib +/intel/common/altpll_bb.v");
			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
		}

		if (flatten && check_label("flatten", "(unless -noflatten)")) {
			run("proc");
			run("flatten");
			run("tribuf -logic");
			run("deminout");
		}

		if (check_label("coarse")) {
			run("synth -run coarse");
		}

		if (!nobram && check_label("bram", "(skip if -nobram)")) {
			run("memory_bram -rules +/intel/common/brams.txt");
			run("techmap -map +/intel/common/brams_map.v");
		}

		if (check_label("fine")) {
			run("opt -fast -mux_undef -undriven -fine -full");
			run("memory_map");
			run("opt -undriven -fine");
			run("dffsr2dff");
			run("dff2dffe -direct-match $_DFF_*");
			run("opt -fine");
			run("techmap -map +/techmap.v");
			run("opt -full");
			run("clean -purge");
			run("setundef -undriven -zero");
			if (retime || help_mode)
				run("abc -markgroups -dff", "(only if -retime)");
		}

		if (check_label("map_luts")) {
			if (family_opt == "a10gx" || family_opt == "cyclonev")
				run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
			else
				run("abc -lut 4" + string(retime ? " -dff" : ""));
			run("clean");
		}

		if (check_label("map_cells")) {
			if (!noiopads)
				run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
			if (family_opt == "max10")
				run("techmap -map +/intel/max10/cells_map.v");
			else if (family_opt == "a10gx")
				run("techmap -map +/intel/a10gx/cells_map.v");
			else if (family_opt == "cyclonev")
				run("techmap -map +/intel/cyclonev/cells_map.v");
			else if (family_opt == "cyclone10")
				run("techmap -map +/intel/cyclone10/cells_map.v");
			else if (family_opt == "cycloneiv")
				run("techmap -map +/intel/cycloneiv/cells_map.v");
			else
				run("techmap -map +/intel/cycloneive/cells_map.v");
			run("dffinit -highlow -ff dffeas q power_up");
			run("clean -purge");
		}

		if (check_label("check")) {
			run("hierarchy -check");
			run("stat");
			run("check -noinit");
		}

		if (check_label("vqm")) {
			if (!vout_file.empty() || help_mode)
				run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
					    help_mode ? "<file-name>" : vout_file.c_str()));
		}

		if (check_label("vpr")) {
			if (!blif_file.empty() || help_mode) {
				run(stringf("opt_clean -purge"));
				run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
			}
		}
	}
} SynthIntelPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>#ifndef TEST_POLYGON_HPP
#define TEST_POLYGON_HPP

#include <gtest/gtest.h>

#include <DO/Core/EigenExtension.hpp>

using namespace DO;

class TestPolygon : public testing::Test
{
protected:
  int w;
  int h;
  double a;
  double b;
  Point2d p1;
  Point2d p2;
  Point2d center;

  TestPolygon()
  {
    w = 512;
    h = 512;

    a = 0.25*w;
    b = 0.75*h;

    p1 = Point2d(a, a);
    p2 = Point2d(b, b);
    center = Point2d(w/2., h/2.);
  }

  template <typename TestPred, typename GroundTruth>
  void sweep_check(const TestPred& pred, const GroundTruth& ground_truth)
  {
    for (int y = -h; y < h; ++y)
    {
      for (int x = -w; x < w; ++x)
      {
        Point2d p(x,y);
        EXPECT_EQ(ground_truth(p), pred(p));
      }
    }
  }

  template <typename TestPred>
  int sweep_count_pixels(const TestPred& pred)
  {
    int quantity = 0;
    for (int y = -h; y < h; ++y)
    {
      for (int x = -w; x < w; ++x)
      {
        Point2d p(x,y);
        if (pred(p))
          ++quantity;
      }
    }
    return quantity;
  }
};

#endif /* TEST_POLYGON_HPP */<commit_msg>Rename data members in test fixture.<commit_after>#ifndef TEST_POLYGON_HPP
#define TEST_POLYGON_HPP

#include <gtest/gtest.h>

#include <DO/Core/EigenExtension.hpp>

using namespace DO;

class TestPolygon : public testing::Test
{
protected:
  int _width;
  int _height;
  double _a;
  double _b;
  Point2d _p1;
  Point2d _p2;
  Point2d _center;

  TestPolygon()
  {
    _width = 10;
    _height = 10;

    _a = 0.25*_width;
    _b = 0.75*_height;

    _p1 = Point2d(_a, _a);
    _p2 = Point2d(_b, _b);
    _center = Point2d(_width/2., _height/2.);
  }

  template <typename TestPred, typename GroundTruth>
  void sweep_check(const TestPred& pred, const GroundTruth& ground_truth)
  {
    for (int y = -_height; y < _height; ++y)
    {
      for (int x = -_width; x < _width; ++x)
      {
        Point2d p(x,y);
        EXPECT_EQ(ground_truth(p), pred(p));
      }
    }
  }

  template <typename TestPred>
  int sweep_count_pixels(const TestPred& pred)
  {
    int quantity = 0;
    for (int y = -_height; y < _height; ++y)
    {
      for (int x = -_width; x < _width; ++x)
      {
        Point2d p(x,y);
        if (pred(p))
          ++quantity;
      }
    }
    return quantity;
  }
};

#endif /* TEST_POLYGON_HPP */<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/common_runtime/eager/kernel_and_device.h"

#include "tensorflow/core/common_runtime/device_factory.h"
#include "tensorflow/core/common_runtime/rendezvous_mgr.h"
#include "tensorflow/core/framework/allocator.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/step_stats.pb.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/gtl/map_util.h"
#include "tensorflow/core/lib/gtl/stl_util.h"
#include "tensorflow/core/platform/fingerprint.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/public/version.h"
#include "tensorflow/core/util/tensor_slice_reader_cache.h"

namespace tensorflow {

// static
Status KernelAndDevice::InitOp(Device* device, const NodeDef& ndef,
                               KernelAndDevice* out) {
  OpKernel* k = nullptr;
  Status s = CreateOpKernel(device->device_type().c_str(), device,
                            device->GetAllocator(AllocatorAttributes()),
                            nullptr, ndef, TF_GRAPH_DEF_VERSION, &k);
  out->device_ = device;
  out->kernel_.reset(k);
  out->flib_ = nullptr;
  return s;
}

// static
Status KernelAndDevice::Init(const NodeDef& ndef, FunctionLibraryRuntime* flib,
                             KernelAndDevice* out) {
  OpKernel* k = nullptr;
  Status s = flib->CreateKernel(ndef, &k);
  out->device_ = flib->device();
  out->kernel_.reset(k);
  out->flib_ = flib;
  return s;
}

Status KernelAndDevice::Run(std::vector<Tensor>* input_tensors,
                            std::vector<Tensor>* output_tensors,
                            NodeExecStats* stats) {
  gtl::InlinedVector<TensorValue, 4> inputs;
  for (Tensor& t : *input_tensors) {
    inputs.push_back(TensorValue(&t));
  }

  std::vector<AllocatorAttributes> out_attrs(kernel_->num_outputs());
  for (size_t i = 0; i < out_attrs.size(); ++i) {
    out_attrs[i].set_on_host(kernel_->output_memory_types()[i] ==
                             tensorflow::HOST_MEMORY);
  }

  OpKernelContext::Params params;
  params.device = device_;
  params.frame_iter = FrameAndIter(0, 0);
  params.inputs = &inputs;
  params.op_kernel = kernel_.get();
  params.resource_manager = device_->resource_manager();
  params.output_attr_array = gtl::vector_as_array(&out_attrs);
  params.function_library = flib_;
  params.slice_reader_cache = &slice_reader_cache_;
  params.rendezvous = rendez_;
  if (stats != nullptr) {
    params.track_allocations = true;
  }
  // TODO(apassos): use a thread pool.
  std::function<void(std::function<void()>)> runner =
      [](std::function<void()> f) { f(); };
  params.runner = &runner;

  OpKernelContext context(&params);

  if (kernel_->def().op() == "_Recv") {
    // TODO(apassos) do not special-case _Recv. Currently the GPU device fails
    // if trying to run _Recv->Compute(), specifically checking for _Recv. To go
    // around this we call _Recv->ComputeAsync, to mimic graph mode behavior.
    AsyncOpKernel* async = kernel_->AsAsync();
    Notification done;
    device_->ComputeAsync(async, &context, [&done]() { done.Notify(); });
    done.WaitForNotification();
  } else {
    device_->Compute(kernel_.get(), &context);
  }
  if (!context.status().ok()) return context.status();

  output_tensors->clear();
  for (int i = 0; i < context.num_outputs(); ++i) {
    output_tensors->push_back(Tensor(*context.mutable_output(i)));
  }
  if (stats != nullptr) {
    for (const auto& allocator_pair : context.wrapped_allocators()) {
      AllocatorMemoryUsed* memory = stats->add_memory();
      memory->set_allocator_name(allocator_pair.first->Name());
      auto sizes = allocator_pair.second->GetSizes();
      memory->set_total_bytes(std::get<0>(sizes));
      memory->set_peak_bytes(std::get<1>(sizes));
      memory->set_live_bytes(std::get<2>(sizes));

      AllocatorStats allocator_stats;
      allocator_pair.first->GetStats(&allocator_stats);
      memory->set_allocator_bytes_in_use(allocator_stats.bytes_in_use);
      allocator_pair.second->GetRecordsAndUnRef();
    }
    auto* ms = stats->mutable_memory_stats();
    ms->set_temp_memory_size(context.temp_memory_allocated());
    for (const auto& alloc_id : context.persistent_alloc_ids()) {
      ms->mutable_persistent_tensor_alloc_ids()->Add(alloc_id);
    }

    ms->set_persistent_memory_size(context.persistent_memory_allocated());
  }
  return Status::OK();
}

}  // namespace tensorflow
<commit_msg>Provide a step container to OpKernelContexts when running eagerly.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/common_runtime/eager/kernel_and_device.h"

#include "tensorflow/core/common_runtime/device_factory.h"
#include "tensorflow/core/common_runtime/rendezvous_mgr.h"
#include "tensorflow/core/framework/allocator.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/resource_mgr.h"
#include "tensorflow/core/framework/step_stats.pb.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/gtl/map_util.h"
#include "tensorflow/core/lib/gtl/stl_util.h"
#include "tensorflow/core/platform/fingerprint.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/public/version.h"
#include "tensorflow/core/util/tensor_slice_reader_cache.h"

namespace tensorflow {

// static
Status KernelAndDevice::InitOp(Device* device, const NodeDef& ndef,
                               KernelAndDevice* out) {
  OpKernel* k = nullptr;
  Status s = CreateOpKernel(device->device_type().c_str(), device,
                            device->GetAllocator(AllocatorAttributes()),
                            nullptr, ndef, TF_GRAPH_DEF_VERSION, &k);
  out->device_ = device;
  out->kernel_.reset(k);
  out->flib_ = nullptr;
  return s;
}

// static
Status KernelAndDevice::Init(const NodeDef& ndef, FunctionLibraryRuntime* flib,
                             KernelAndDevice* out) {
  OpKernel* k = nullptr;
  Status s = flib->CreateKernel(ndef, &k);
  out->device_ = flib->device();
  out->kernel_.reset(k);
  out->flib_ = flib;
  return s;
}

Status KernelAndDevice::Run(std::vector<Tensor>* input_tensors,
                            std::vector<Tensor>* output_tensors,
                            NodeExecStats* stats) {
  gtl::InlinedVector<TensorValue, 4> inputs;
  for (Tensor& t : *input_tensors) {
    inputs.push_back(TensorValue(&t));
  }

  std::vector<AllocatorAttributes> out_attrs(kernel_->num_outputs());
  for (size_t i = 0; i < out_attrs.size(); ++i) {
    out_attrs[i].set_on_host(kernel_->output_memory_types()[i] ==
                             tensorflow::HOST_MEMORY);
  }

  OpKernelContext::Params params;
  params.device = device_;
  params.frame_iter = FrameAndIter(0, 0);
  params.inputs = &inputs;
  params.op_kernel = kernel_.get();
  params.resource_manager = device_->resource_manager();
  params.output_attr_array = gtl::vector_as_array(&out_attrs);
  params.function_library = flib_;
  params.slice_reader_cache = &slice_reader_cache_;
  params.rendezvous = rendez_;
  if (stats != nullptr) {
    params.track_allocations = true;
  }
  // TODO(apassos): use a thread pool.
  std::function<void(std::function<void()>)> runner =
      [](std::function<void()> f) { f(); };
  params.runner = &runner;

  ScopedStepContainer step_container(0, [this](const string& name) {
    device_->resource_manager()->Cleanup(name).IgnoreError();
  });
  params.step_container = &step_container;

  OpKernelContext context(&params);

  if (kernel_->def().op() == "_Recv") {
    // TODO(apassos) do not special-case _Recv. Currently the GPU device fails
    // if trying to run _Recv->Compute(), specifically checking for _Recv. To go
    // around this we call _Recv->ComputeAsync, to mimic graph mode behavior.
    AsyncOpKernel* async = kernel_->AsAsync();
    Notification done;
    device_->ComputeAsync(async, &context, [&done]() { done.Notify(); });
    done.WaitForNotification();
  } else {
    device_->Compute(kernel_.get(), &context);
  }
  if (!context.status().ok()) return context.status();

  output_tensors->clear();
  for (int i = 0; i < context.num_outputs(); ++i) {
    output_tensors->push_back(Tensor(*context.mutable_output(i)));
  }
  if (stats != nullptr) {
    for (const auto& allocator_pair : context.wrapped_allocators()) {
      AllocatorMemoryUsed* memory = stats->add_memory();
      memory->set_allocator_name(allocator_pair.first->Name());
      auto sizes = allocator_pair.second->GetSizes();
      memory->set_total_bytes(std::get<0>(sizes));
      memory->set_peak_bytes(std::get<1>(sizes));
      memory->set_live_bytes(std::get<2>(sizes));

      AllocatorStats allocator_stats;
      allocator_pair.first->GetStats(&allocator_stats);
      memory->set_allocator_bytes_in_use(allocator_stats.bytes_in_use);
      allocator_pair.second->GetRecordsAndUnRef();
    }
    auto* ms = stats->mutable_memory_stats();
    ms->set_temp_memory_size(context.temp_memory_allocated());
    for (const auto& alloc_id : context.persistent_alloc_ids()) {
      ms->mutable_persistent_tensor_alloc_ids()->Add(alloc_id);
    }

    ms->set_persistent_memory_size(context.persistent_memory_allocated());
  }
  return Status::OK();
}

}  // namespace tensorflow
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: property.cxx,v $
 *
 *  $Revision: 1.16 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 23:58:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_forms.hxx"

#ifndef FRM_STRINGS_HXX
#include "frm_strings.hxx"
#endif

#ifndef _FRM_PROPERTY_HXX_
#include "property.hxx"
#endif

#ifndef _FRM_PROPERTY_HRC_
#include "property.hrc"
#endif

#ifndef _CPPUHELPER_QUERYINTERFACE_HXX_
#include <cppuhelper/queryinterface.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif

#include <algorithm>

//... namespace frm .......................................................
namespace frm
{
//.........................................................................

//==================================================================
//= PropertyInfoService
//==================================================================
PropertyInfoService::PropertyMap PropertyInfoService::s_AllKnownProperties;
//------------------------------------------------------------------
sal_Int32 PropertyInfoService::getPropertyId(const ::rtl::OUString& _rName)
{
    initialize();

    PropertyAssignment aCompareName(_rName, -1);

    ::std::pair<PropertyMapIterator,PropertyMapIterator> aPair = equal_range(
        s_AllKnownProperties.begin(),
        s_AllKnownProperties.end(),
        aCompareName,
        PropertyAssignmentNameCompareLess());

    sal_Int32 nHandle = -1;
    if (aPair.first != aPair.second)
    {   // we found something _and_ we have an identity
        nHandle = aPair.first->nHandle;
    }

    return nHandle;
}

//------------------------------------------------------------------
sal_Int32 ConcretInfoService::getPreferedPropertyId(const ::rtl::OUString& _rName)
{
    return PropertyInfoService::getPropertyId(_rName);
}

//------------------------------------------------------------------
#define ADD_PROP_ASSIGNMENT(varname) \
    s_AllKnownProperties.push_back(PropertyAssignment(PROPERTY_##varname, PROPERTY_ID_##varname))
//..................................................................
void PropertyInfoService::initialize()
{
    if (!s_AllKnownProperties.empty())
        return;

    s_AllKnownProperties.reserve(220);

    ADD_PROP_ASSIGNMENT(NAME);
    ADD_PROP_ASSIGNMENT(TAG);
    ADD_PROP_ASSIGNMENT(TABINDEX);
    ADD_PROP_ASSIGNMENT(CLASSID);
    ADD_PROP_ASSIGNMENT(ALIGN);
    ADD_PROP_ASSIGNMENT(FETCHSIZE);
    ADD_PROP_ASSIGNMENT(VALUE);
    ADD_PROP_ASSIGNMENT(VALUEMIN);
    ADD_PROP_ASSIGNMENT(VALUEMAX);
    ADD_PROP_ASSIGNMENT(VALUESTEP);
    ADD_PROP_ASSIGNMENT(TEXT);
    ADD_PROP_ASSIGNMENT(LABEL);
    ADD_PROP_ASSIGNMENT(NAVIGATION);
    ADD_PROP_ASSIGNMENT(CYCLE);
    ADD_PROP_ASSIGNMENT(CONTROLSOURCE);
    ADD_PROP_ASSIGNMENT(ENABLED);
    ADD_PROP_ASSIGNMENT(SPIN);
    ADD_PROP_ASSIGNMENT(READONLY);
    ADD_PROP_ASSIGNMENT(FILTER);
    ADD_PROP_ASSIGNMENT(WIDTH);
    ADD_PROP_ASSIGNMENT(SEARCHABLE);
    ADD_PROP_ASSIGNMENT(MULTILINE);
    ADD_PROP_ASSIGNMENT(TARGET_URL);
    ADD_PROP_ASSIGNMENT(DEFAULTCONTROL);
    ADD_PROP_ASSIGNMENT(MAXTEXTLEN);
    ADD_PROP_ASSIGNMENT(SIZE);
    ADD_PROP_ASSIGNMENT(DATE);
    ADD_PROP_ASSIGNMENT(TIME);
    ADD_PROP_ASSIGNMENT(STATE);
    ADD_PROP_ASSIGNMENT(TRISTATE);
    ADD_PROP_ASSIGNMENT(HIDDEN_VALUE);
    ADD_PROP_ASSIGNMENT(TARGET_FRAME);
    ADD_PROP_ASSIGNMENT(BUTTONTYPE);
    ADD_PROP_ASSIGNMENT(STRINGITEMLIST);
    ADD_PROP_ASSIGNMENT(DEFAULT_TEXT);
    ADD_PROP_ASSIGNMENT(DEFAULTCHECKED);
    ADD_PROP_ASSIGNMENT(DEFAULT_DATE);
    ADD_PROP_ASSIGNMENT(DEFAULT_TIME);
    ADD_PROP_ASSIGNMENT(DEFAULT_VALUE);
    ADD_PROP_ASSIGNMENT(FORMATKEY);
    ADD_PROP_ASSIGNMENT(FORMATSSUPPLIER);
    ADD_PROP_ASSIGNMENT(SUBMIT_ACTION);
    ADD_PROP_ASSIGNMENT(SUBMIT_TARGET);
    ADD_PROP_ASSIGNMENT(SUBMIT_METHOD);
    ADD_PROP_ASSIGNMENT(SUBMIT_ENCODING);
    ADD_PROP_ASSIGNMENT(IMAGE_URL);
    ADD_PROP_ASSIGNMENT(EMPTY_IS_NULL);
    ADD_PROP_ASSIGNMENT(LISTSOURCETYPE);
    ADD_PROP_ASSIGNMENT(LISTSOURCE);
    ADD_PROP_ASSIGNMENT(SELECT_SEQ);
    ADD_PROP_ASSIGNMENT(VALUE_SEQ);
    ADD_PROP_ASSIGNMENT(DEFAULT_SELECT_SEQ);
    ADD_PROP_ASSIGNMENT(MULTISELECTION);
    ADD_PROP_ASSIGNMENT(DECIMAL_ACCURACY);
    ADD_PROP_ASSIGNMENT(EDITMASK);
    ADD_PROP_ASSIGNMENT(ISREADONLY);
    ADD_PROP_ASSIGNMENT(FIELDTYPE);
    ADD_PROP_ASSIGNMENT(DECIMALS);
    ADD_PROP_ASSIGNMENT(REFVALUE);
    ADD_PROP_ASSIGNMENT(STRICTFORMAT);
    ADD_PROP_ASSIGNMENT(DATASOURCE);
    ADD_PROP_ASSIGNMENT(ALLOWADDITIONS);
    ADD_PROP_ASSIGNMENT(ALLOWEDITS);
    ADD_PROP_ASSIGNMENT(ALLOWDELETIONS);
    ADD_PROP_ASSIGNMENT(MASTERFIELDS);
    ADD_PROP_ASSIGNMENT(ISPASSTHROUGH);
    ADD_PROP_ASSIGNMENT(QUERY);
    ADD_PROP_ASSIGNMENT(LITERALMASK);
    ADD_PROP_ASSIGNMENT(SHOWTHOUSANDSEP);
    ADD_PROP_ASSIGNMENT(CURRENCYSYMBOL);
    ADD_PROP_ASSIGNMENT(DATEFORMAT);
    ADD_PROP_ASSIGNMENT(DATEMIN);
    ADD_PROP_ASSIGNMENT(DATEMAX);
    ADD_PROP_ASSIGNMENT(DATE_SHOW_CENTURY);
    ADD_PROP_ASSIGNMENT(TIMEFORMAT);
    ADD_PROP_ASSIGNMENT(TIMEMIN);
    ADD_PROP_ASSIGNMENT(TIMEMAX);
    ADD_PROP_ASSIGNMENT(LINECOUNT);
    ADD_PROP_ASSIGNMENT(BOUNDCOLUMN);
    ADD_PROP_ASSIGNMENT(HASNAVIGATION);
    ADD_PROP_ASSIGNMENT(FONT);
    ADD_PROP_ASSIGNMENT(BACKGROUNDCOLOR);
    ADD_PROP_ASSIGNMENT(FILLCOLOR);
    ADD_PROP_ASSIGNMENT(TEXTCOLOR);
    ADD_PROP_ASSIGNMENT(LINECOLOR);
    ADD_PROP_ASSIGNMENT(BORDER);
    ADD_PROP_ASSIGNMENT(DROPDOWN);
    ADD_PROP_ASSIGNMENT(HSCROLL);
    ADD_PROP_ASSIGNMENT(VSCROLL);
    ADD_PROP_ASSIGNMENT(TABSTOP);
    ADD_PROP_ASSIGNMENT(AUTOCOMPLETE);
    ADD_PROP_ASSIGNMENT(HARDLINEBREAKS);
    ADD_PROP_ASSIGNMENT(PRINTABLE);
    ADD_PROP_ASSIGNMENT(ECHO_CHAR);
    ADD_PROP_ASSIGNMENT(ROWHEIGHT);
    ADD_PROP_ASSIGNMENT(HELPTEXT);
    ADD_PROP_ASSIGNMENT(FONT_NAME);
    ADD_PROP_ASSIGNMENT(FONT_STYLENAME);
    ADD_PROP_ASSIGNMENT(FONT_FAMILY);
    ADD_PROP_ASSIGNMENT(FONT_CHARSET);
    ADD_PROP_ASSIGNMENT(FONT_HEIGHT);
    ADD_PROP_ASSIGNMENT(FONT_WEIGHT);
    ADD_PROP_ASSIGNMENT(FONT_SLANT);
    ADD_PROP_ASSIGNMENT(FONT_UNDERLINE);
    ADD_PROP_ASSIGNMENT(FONT_WORDLINEMODE);
    ADD_PROP_ASSIGNMENT(FONT_STRIKEOUT);
    ADD_PROP_ASSIGNMENT(TEXTLINECOLOR);
    ADD_PROP_ASSIGNMENT(FONTEMPHASISMARK);
    ADD_PROP_ASSIGNMENT(FONTRELIEF);
    ADD_PROP_ASSIGNMENT(HELPURL);
    ADD_PROP_ASSIGNMENT(RECORDMARKER);
    ADD_PROP_ASSIGNMENT(BOUNDFIELD);
    ADD_PROP_ASSIGNMENT(TREATASNUMERIC);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_VALUE);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_DEFAULT);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_MIN);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_MAX);
    ADD_PROP_ASSIGNMENT(HIDDEN);
    ADD_PROP_ASSIGNMENT(FILTERPROPOSAL);
    ADD_PROP_ASSIGNMENT(FIELDSOURCE);
    ADD_PROP_ASSIGNMENT(TABLENAME);
    ADD_PROP_ASSIGNMENT(CONTROLLABEL);
    ADD_PROP_ASSIGNMENT(CURRSYM_POSITION);
    ADD_PROP_ASSIGNMENT(CURSORCOLOR);
    ADD_PROP_ASSIGNMENT(ALWAYSSHOWCURSOR);
    ADD_PROP_ASSIGNMENT(DISPLAYSYNCHRON);
    ADD_PROP_ASSIGNMENT(ISMODIFIED);
    ADD_PROP_ASSIGNMENT(ISNEW);
    ADD_PROP_ASSIGNMENT(PRIVILEGES);
    ADD_PROP_ASSIGNMENT(DETAILFIELDS);
    ADD_PROP_ASSIGNMENT(COMMAND);
    ADD_PROP_ASSIGNMENT(COMMANDTYPE);
    ADD_PROP_ASSIGNMENT(RESULTSET_CONCURRENCY);
    ADD_PROP_ASSIGNMENT(INSERTONLY);
    ADD_PROP_ASSIGNMENT(RESULTSET_TYPE);
    ADD_PROP_ASSIGNMENT(ESCAPE_PROCESSING);
    ADD_PROP_ASSIGNMENT(APPLYFILTER);
    ADD_PROP_ASSIGNMENT(ISNULLABLE);
    ADD_PROP_ASSIGNMENT(ACTIVECOMMAND);
    ADD_PROP_ASSIGNMENT(ISCURRENCY);
    ADD_PROP_ASSIGNMENT(URL);
    ADD_PROP_ASSIGNMENT(TITLE);
    ADD_PROP_ASSIGNMENT(ACTIVE_CONNECTION);
    ADD_PROP_ASSIGNMENT(SCALE);
    ADD_PROP_ASSIGNMENT(SORT);
    ADD_PROP_ASSIGNMENT(PERSISTENCE_MAXTEXTLENGTH);
    ADD_PROP_ASSIGNMENT(SCROLL_VALUE);
    ADD_PROP_ASSIGNMENT(SPIN_VALUE);
    ADD_PROP_ASSIGNMENT(DEFAULT_SCROLL_VALUE);
    ADD_PROP_ASSIGNMENT(DEFAULT_SPIN_VALUE);

    // now sort the array by name

    std::sort(
        s_AllKnownProperties.begin(),
        s_AllKnownProperties.end(),
        PropertyAssignmentNameCompareLess()
    );
}

//.........................................................................
}
//... namespace frm .......................................................

<commit_msg>INTEGRATION: CWS dba23a (1.16.58); FILE MERGED 2007/03/14 14:44:52 fs 1.16.58.1: #i74087# outsourced the PropertyBag handling into an own class, which is now used by both OControlModel and ODatabaseForm<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: property.cxx,v $
 *
 *  $Revision: 1.17 $
 *
 *  last change: $Author: kz $ $Date: 2007-05-10 09:59:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_forms.hxx"

#ifndef FRM_STRINGS_HXX
#include "frm_strings.hxx"
#endif

#ifndef _FRM_PROPERTY_HXX_
#include "property.hxx"
#endif

#ifndef _FRM_PROPERTY_HRC_
#include "property.hrc"
#endif

#ifndef _CPPUHELPER_QUERYINTERFACE_HXX_
#include <cppuhelper/queryinterface.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif

#include <algorithm>

//... namespace frm .......................................................
namespace frm
{
//.........................................................................

//==================================================================
//= PropertyInfoService
//==================================================================
PropertyInfoService::PropertyMap PropertyInfoService::s_AllKnownProperties;
//------------------------------------------------------------------
sal_Int32 PropertyInfoService::getPropertyId(const ::rtl::OUString& _rName)
{
    initialize();

    PropertyAssignment aCompareName(_rName, -1);

    ::std::pair<PropertyMapIterator,PropertyMapIterator> aPair = equal_range(
        s_AllKnownProperties.begin(),
        s_AllKnownProperties.end(),
        aCompareName,
        PropertyAssignmentNameCompareLess());

    sal_Int32 nHandle = -1;
    if (aPair.first != aPair.second)
    {   // we found something _and_ we have an identity
        nHandle = aPair.first->nHandle;
    }

    return nHandle;
}

//------------------------------------------------------------------
sal_Int32 ConcreteInfoService::getPreferedPropertyId(const ::rtl::OUString& _rName)
{
    return PropertyInfoService::getPropertyId(_rName);
}

//------------------------------------------------------------------
#define ADD_PROP_ASSIGNMENT(varname) \
    s_AllKnownProperties.push_back(PropertyAssignment(PROPERTY_##varname, PROPERTY_ID_##varname))
//..................................................................
void PropertyInfoService::initialize()
{
    if (!s_AllKnownProperties.empty())
        return;

    s_AllKnownProperties.reserve(220);

    ADD_PROP_ASSIGNMENT(NAME);
    ADD_PROP_ASSIGNMENT(TAG);
    ADD_PROP_ASSIGNMENT(TABINDEX);
    ADD_PROP_ASSIGNMENT(CLASSID);
    ADD_PROP_ASSIGNMENT(ALIGN);
    ADD_PROP_ASSIGNMENT(FETCHSIZE);
    ADD_PROP_ASSIGNMENT(VALUE);
    ADD_PROP_ASSIGNMENT(VALUEMIN);
    ADD_PROP_ASSIGNMENT(VALUEMAX);
    ADD_PROP_ASSIGNMENT(VALUESTEP);
    ADD_PROP_ASSIGNMENT(TEXT);
    ADD_PROP_ASSIGNMENT(LABEL);
    ADD_PROP_ASSIGNMENT(NAVIGATION);
    ADD_PROP_ASSIGNMENT(CYCLE);
    ADD_PROP_ASSIGNMENT(CONTROLSOURCE);
    ADD_PROP_ASSIGNMENT(ENABLED);
    ADD_PROP_ASSIGNMENT(SPIN);
    ADD_PROP_ASSIGNMENT(READONLY);
    ADD_PROP_ASSIGNMENT(FILTER);
    ADD_PROP_ASSIGNMENT(WIDTH);
    ADD_PROP_ASSIGNMENT(SEARCHABLE);
    ADD_PROP_ASSIGNMENT(MULTILINE);
    ADD_PROP_ASSIGNMENT(TARGET_URL);
    ADD_PROP_ASSIGNMENT(DEFAULTCONTROL);
    ADD_PROP_ASSIGNMENT(MAXTEXTLEN);
    ADD_PROP_ASSIGNMENT(SIZE);
    ADD_PROP_ASSIGNMENT(DATE);
    ADD_PROP_ASSIGNMENT(TIME);
    ADD_PROP_ASSIGNMENT(STATE);
    ADD_PROP_ASSIGNMENT(TRISTATE);
    ADD_PROP_ASSIGNMENT(HIDDEN_VALUE);
    ADD_PROP_ASSIGNMENT(TARGET_FRAME);
    ADD_PROP_ASSIGNMENT(BUTTONTYPE);
    ADD_PROP_ASSIGNMENT(STRINGITEMLIST);
    ADD_PROP_ASSIGNMENT(DEFAULT_TEXT);
    ADD_PROP_ASSIGNMENT(DEFAULTCHECKED);
    ADD_PROP_ASSIGNMENT(DEFAULT_DATE);
    ADD_PROP_ASSIGNMENT(DEFAULT_TIME);
    ADD_PROP_ASSIGNMENT(DEFAULT_VALUE);
    ADD_PROP_ASSIGNMENT(FORMATKEY);
    ADD_PROP_ASSIGNMENT(FORMATSSUPPLIER);
    ADD_PROP_ASSIGNMENT(SUBMIT_ACTION);
    ADD_PROP_ASSIGNMENT(SUBMIT_TARGET);
    ADD_PROP_ASSIGNMENT(SUBMIT_METHOD);
    ADD_PROP_ASSIGNMENT(SUBMIT_ENCODING);
    ADD_PROP_ASSIGNMENT(IMAGE_URL);
    ADD_PROP_ASSIGNMENT(EMPTY_IS_NULL);
    ADD_PROP_ASSIGNMENT(LISTSOURCETYPE);
    ADD_PROP_ASSIGNMENT(LISTSOURCE);
    ADD_PROP_ASSIGNMENT(SELECT_SEQ);
    ADD_PROP_ASSIGNMENT(VALUE_SEQ);
    ADD_PROP_ASSIGNMENT(DEFAULT_SELECT_SEQ);
    ADD_PROP_ASSIGNMENT(MULTISELECTION);
    ADD_PROP_ASSIGNMENT(DECIMAL_ACCURACY);
    ADD_PROP_ASSIGNMENT(EDITMASK);
    ADD_PROP_ASSIGNMENT(ISREADONLY);
    ADD_PROP_ASSIGNMENT(FIELDTYPE);
    ADD_PROP_ASSIGNMENT(DECIMALS);
    ADD_PROP_ASSIGNMENT(REFVALUE);
    ADD_PROP_ASSIGNMENT(STRICTFORMAT);
    ADD_PROP_ASSIGNMENT(DATASOURCE);
    ADD_PROP_ASSIGNMENT(ALLOWADDITIONS);
    ADD_PROP_ASSIGNMENT(ALLOWEDITS);
    ADD_PROP_ASSIGNMENT(ALLOWDELETIONS);
    ADD_PROP_ASSIGNMENT(MASTERFIELDS);
    ADD_PROP_ASSIGNMENT(ISPASSTHROUGH);
    ADD_PROP_ASSIGNMENT(QUERY);
    ADD_PROP_ASSIGNMENT(LITERALMASK);
    ADD_PROP_ASSIGNMENT(SHOWTHOUSANDSEP);
    ADD_PROP_ASSIGNMENT(CURRENCYSYMBOL);
    ADD_PROP_ASSIGNMENT(DATEFORMAT);
    ADD_PROP_ASSIGNMENT(DATEMIN);
    ADD_PROP_ASSIGNMENT(DATEMAX);
    ADD_PROP_ASSIGNMENT(DATE_SHOW_CENTURY);
    ADD_PROP_ASSIGNMENT(TIMEFORMAT);
    ADD_PROP_ASSIGNMENT(TIMEMIN);
    ADD_PROP_ASSIGNMENT(TIMEMAX);
    ADD_PROP_ASSIGNMENT(LINECOUNT);
    ADD_PROP_ASSIGNMENT(BOUNDCOLUMN);
    ADD_PROP_ASSIGNMENT(HASNAVIGATION);
    ADD_PROP_ASSIGNMENT(FONT);
    ADD_PROP_ASSIGNMENT(BACKGROUNDCOLOR);
    ADD_PROP_ASSIGNMENT(FILLCOLOR);
    ADD_PROP_ASSIGNMENT(TEXTCOLOR);
    ADD_PROP_ASSIGNMENT(LINECOLOR);
    ADD_PROP_ASSIGNMENT(BORDER);
    ADD_PROP_ASSIGNMENT(DROPDOWN);
    ADD_PROP_ASSIGNMENT(HSCROLL);
    ADD_PROP_ASSIGNMENT(VSCROLL);
    ADD_PROP_ASSIGNMENT(TABSTOP);
    ADD_PROP_ASSIGNMENT(AUTOCOMPLETE);
    ADD_PROP_ASSIGNMENT(HARDLINEBREAKS);
    ADD_PROP_ASSIGNMENT(PRINTABLE);
    ADD_PROP_ASSIGNMENT(ECHO_CHAR);
    ADD_PROP_ASSIGNMENT(ROWHEIGHT);
    ADD_PROP_ASSIGNMENT(HELPTEXT);
    ADD_PROP_ASSIGNMENT(FONT_NAME);
    ADD_PROP_ASSIGNMENT(FONT_STYLENAME);
    ADD_PROP_ASSIGNMENT(FONT_FAMILY);
    ADD_PROP_ASSIGNMENT(FONT_CHARSET);
    ADD_PROP_ASSIGNMENT(FONT_HEIGHT);
    ADD_PROP_ASSIGNMENT(FONT_WEIGHT);
    ADD_PROP_ASSIGNMENT(FONT_SLANT);
    ADD_PROP_ASSIGNMENT(FONT_UNDERLINE);
    ADD_PROP_ASSIGNMENT(FONT_WORDLINEMODE);
    ADD_PROP_ASSIGNMENT(FONT_STRIKEOUT);
    ADD_PROP_ASSIGNMENT(TEXTLINECOLOR);
    ADD_PROP_ASSIGNMENT(FONTEMPHASISMARK);
    ADD_PROP_ASSIGNMENT(FONTRELIEF);
    ADD_PROP_ASSIGNMENT(HELPURL);
    ADD_PROP_ASSIGNMENT(RECORDMARKER);
    ADD_PROP_ASSIGNMENT(BOUNDFIELD);
    ADD_PROP_ASSIGNMENT(TREATASNUMERIC);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_VALUE);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_DEFAULT);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_MIN);
    ADD_PROP_ASSIGNMENT(EFFECTIVE_MAX);
    ADD_PROP_ASSIGNMENT(HIDDEN);
    ADD_PROP_ASSIGNMENT(FILTERPROPOSAL);
    ADD_PROP_ASSIGNMENT(FIELDSOURCE);
    ADD_PROP_ASSIGNMENT(TABLENAME);
    ADD_PROP_ASSIGNMENT(CONTROLLABEL);
    ADD_PROP_ASSIGNMENT(CURRSYM_POSITION);
    ADD_PROP_ASSIGNMENT(CURSORCOLOR);
    ADD_PROP_ASSIGNMENT(ALWAYSSHOWCURSOR);
    ADD_PROP_ASSIGNMENT(DISPLAYSYNCHRON);
    ADD_PROP_ASSIGNMENT(ISMODIFIED);
    ADD_PROP_ASSIGNMENT(ISNEW);
    ADD_PROP_ASSIGNMENT(PRIVILEGES);
    ADD_PROP_ASSIGNMENT(DETAILFIELDS);
    ADD_PROP_ASSIGNMENT(COMMAND);
    ADD_PROP_ASSIGNMENT(COMMANDTYPE);
    ADD_PROP_ASSIGNMENT(RESULTSET_CONCURRENCY);
    ADD_PROP_ASSIGNMENT(INSERTONLY);
    ADD_PROP_ASSIGNMENT(RESULTSET_TYPE);
    ADD_PROP_ASSIGNMENT(ESCAPE_PROCESSING);
    ADD_PROP_ASSIGNMENT(APPLYFILTER);
    ADD_PROP_ASSIGNMENT(ISNULLABLE);
    ADD_PROP_ASSIGNMENT(ACTIVECOMMAND);
    ADD_PROP_ASSIGNMENT(ISCURRENCY);
    ADD_PROP_ASSIGNMENT(URL);
    ADD_PROP_ASSIGNMENT(TITLE);
    ADD_PROP_ASSIGNMENT(ACTIVE_CONNECTION);
    ADD_PROP_ASSIGNMENT(SCALE);
    ADD_PROP_ASSIGNMENT(SORT);
    ADD_PROP_ASSIGNMENT(PERSISTENCE_MAXTEXTLENGTH);
    ADD_PROP_ASSIGNMENT(SCROLL_VALUE);
    ADD_PROP_ASSIGNMENT(SPIN_VALUE);
    ADD_PROP_ASSIGNMENT(DEFAULT_SCROLL_VALUE);
    ADD_PROP_ASSIGNMENT(DEFAULT_SPIN_VALUE);

    // now sort the array by name

    std::sort(
        s_AllKnownProperties.begin(),
        s_AllKnownProperties.end(),
        PropertyAssignmentNameCompareLess()
    );
}

//.........................................................................
}
//... namespace frm .......................................................

<|endoftext|>


<commit_before>/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __STOUT_CACHE_HPP__
#define __STOUT_CACHE_HPP__

#include <functional>
#include <iostream>
#include <list>
#include <map>

#include <boost/unordered_map.hpp>

#include "none.hpp"
#include "option.hpp"

// Forward declaration.
template <typename Key, typename Value>
class cache;

// Outputs the key/value pairs from least to most-recently used.
template <typename Key, typename Value>
std::ostream& operator << (
    std::ostream& stream,
    const cache<Key, Value>& c);

// Provides a least-recently used (LRU) cache of some predefined
// capacity. A "write" and a "read" both count as uses.
template <typename Key, typename Value>
class cache
{
public:
  typedef std::list<Key> list;
  typedef boost::unordered_map<
    Key, std::pair<Value, typename list::iterator> > map;

  explicit cache(int _capacity) : capacity(_capacity) {}

  void put(const Key& key, const Value& value)
  {
    typename map::iterator i = values.find(key);
    if (i == values.end()) {
      insert(key, value);
    } else {
      (*i).second.first = value;
      use(i);
    }
  }

  Option<Value> get(const Key& key)
  {
    typename map::iterator i = values.find(key);

    if (i != values.end()) {
      use(i);
      return (*i).second.first;
    }

    return None();
  }

private:
  // Not copyable, not assignable.
  cache(const cache&);
  cache& operator = (const cache&);

  // Give the operator access to our internals.
  friend std::ostream& operator << <>(
      std::ostream& stream,
      const cache<Key, Value>& c);

  // Insert key/value into the cache.
  void insert(const Key& key, const Value& value)
  {
    if (keys.size() == capacity) {
      evict();
    }

    // Get a "pointer" into the lru list for efficient update.
    typename list::iterator i = keys.insert(keys.end(), key);

    // Save key/value and "pointer" into lru list.
    values.insert(std::make_pair(key, std::make_pair(value, i)));
  }

  // Updates the LRU ordering in the cache for the given iterator.
  void use(const typename map::iterator& i)
  {
    // Move the "pointer" to the end of the lru list.
    keys.splice(keys.end(), keys, (*i).second.second);

    // Now update the "pointer" so we can do this again.
    (*i).second.second = --keys.end();
  }

  // Evict the least-recently used element from the cache.
  void evict()
  {
    const typename map::iterator& i = values.find(keys.front());
    CHECK(i != values.end());
    values.erase(i);
    keys.pop_front();
  }

  // Size of the cache.
  int capacity;

  // Cache of values and "pointers" into the least-recently used list.
  map values;

  // Keys ordered by least-recently used.
  list keys;
};

template <typename Key, typename Value>
std::ostream& operator << (
    std::ostream& stream,
    const cache<Key, Value>& c)
{
  typename cache<Key, Value>::list::const_iterator i1;
  for (i1 = c.keys.begin(); i1 != c.keys.end(); i1++) {
    stream << *i1 << ": ";
    typename cache<Key, Value>::map::const_iterator i2;
    i2 = c.values.find(*i1);
    CHECK(i2 != c.values.end());
    stream << *i2 << std::endl;
  }
  return stream;
}

#endif // __STOUT_CACHE_HPP__
<commit_msg>Renamed cache to Cache.<commit_after>/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __STOUT_CACHE_HPP__
#define __STOUT_CACHE_HPP__

#include <functional>
#include <iostream>
#include <list>
#include <map>

#include <boost/unordered_map.hpp>

#include "none.hpp"
#include "option.hpp"

// Forward declaration.
template <typename Key, typename Value>
class Cache;

// Outputs the key/value pairs from least to most-recently used.
template <typename Key, typename Value>
std::ostream& operator << (
    std::ostream& stream,
    const Cache<Key, Value>& c);

// Provides a least-recently used (LRU) cache of some predefined
// capacity. A "write" and a "read" both count as uses.
template <typename Key, typename Value>
class Cache
{
public:
  typedef std::list<Key> list;
  typedef boost::unordered_map<
    Key, std::pair<Value, typename list::iterator> > map;

  explicit Cache(int _capacity) : capacity(_capacity) {}

  void put(const Key& key, const Value& value)
  {
    typename map::iterator i = values.find(key);
    if (i == values.end()) {
      insert(key, value);
    } else {
      (*i).second.first = value;
      use(i);
    }
  }

  Option<Value> get(const Key& key)
  {
    typename map::iterator i = values.find(key);

    if (i != values.end()) {
      use(i);
      return (*i).second.first;
    }

    return None();
  }

private:
  // Not copyable, not assignable.
  Cache(const Cache&);
  Cache& operator = (const Cache&);

  // Give the operator access to our internals.
  friend std::ostream& operator << <>(
      std::ostream& stream,
      const Cache<Key, Value>& c);

  // Insert key/value into the cache.
  void insert(const Key& key, const Value& value)
  {
    if (keys.size() == capacity) {
      evict();
    }

    // Get a "pointer" into the lru list for efficient update.
    typename list::iterator i = keys.insert(keys.end(), key);

    // Save key/value and "pointer" into lru list.
    values.insert(std::make_pair(key, std::make_pair(value, i)));
  }

  // Updates the LRU ordering in the cache for the given iterator.
  void use(const typename map::iterator& i)
  {
    // Move the "pointer" to the end of the lru list.
    keys.splice(keys.end(), keys, (*i).second.second);

    // Now update the "pointer" so we can do this again.
    (*i).second.second = --keys.end();
  }

  // Evict the least-recently used element from the cache.
  void evict()
  {
    const typename map::iterator& i = values.find(keys.front());
    CHECK(i != values.end());
    values.erase(i);
    keys.pop_front();
  }

  // Size of the cache.
  int capacity;

  // Cache of values and "pointers" into the least-recently used list.
  map values;

  // Keys ordered by least-recently used.
  list keys;
};

template <typename Key, typename Value>
std::ostream& operator << (
    std::ostream& stream,
    const Cache<Key, Value>& c)
{
  typename Cache<Key, Value>::list::const_iterator i1;
  for (i1 = c.keys.begin(); i1 != c.keys.end(); i1++) {
    stream << *i1 << ": ";
    typename Cache<Key, Value>::map::const_iterator i2;
    i2 = c.values.find(*i1);
    CHECK(i2 != c.values.end());
    stream << *i2 << std::endl;
  }
  return stream;
}

#endif // __STOUT_CACHE_HPP__
<|endoftext|>