<commit_before>/*
 * D. Lizards and Basements 2
 * time limit per test2 seconds
 * memory limit per test64 megabytes
 * inputstandard input
 * outputstandard output
 * This is simplified version of the problem used on the original contest. The original problem seems to have too difiicult solution. The constraints for input data have been reduced.
 *
 * Polycarp likes to play computer role-playing game «Lizards and Basements». At the moment he is playing it as a magician. At one of the last levels he has to fight the line of archers. The only spell with which he can damage them is a fire ball. If Polycarp hits the i-th archer with his fire ball (they are numbered from left to right), the archer loses a health points. At the same time the spell damages the archers adjacent to the i-th (if any) — they lose b (1 ≤ b < a ≤ 10) health points each.
 *
 * As the extreme archers (i.e. archers numbered 1 and n) are very far, the fire ball cannot reach them. Polycarp can hit any other archer with his fire ball.
 *
 * The amount of health points for each archer is known. An archer will be killed when this amount is less than 0. What is the minimum amount of spells Polycarp can use to kill all the enemies?
 *
 * Polycarp can throw his fire ball into an archer if the latter is already killed.
 *
 * Input
 * The first line of the input contains three integers n, a, b (3 ≤ n ≤ 10; 1 ≤ b < a ≤ 10). The second line contains a sequence of n integers — h1, h2, ..., hn (1 ≤ hi ≤ 15), where hi is the amount of health points the i-th archer has.
 *
 * Output
 * In the first line print t — the required minimum amount of fire balls.
 *
 * In the second line print t numbers — indexes of the archers that Polycarp should hit to kill all the archers in t shots. All these numbers should be between 2 and n - 1. Separate numbers with spaces. If there are several solutions, output any of them. Print numbers in any order.
 *
 * Examples
 * input
 * 3 2 1
 * 2 2 2
 * output
 * 3
 * 2 2 2
 * input
 * 4 3 1
 * 1 4 1 1
 * output
 * 4
 * 2 2 3 3
 * */

int main() {
    return 0;
}
<commit_msg>submit cf 6d dp<commit_after>/*
 * D. Lizards and Basements 2
 * time limit per test2 seconds
 * memory limit per test64 megabytes
 * inputstandard input
 * outputstandard output
 * This is simplified version of the problem used on the original contest. The original problem seems to have too difiicult solution. The constraints for input data have been reduced.
 *
 * Polycarp likes to play computer role-playing game «Lizards and Basements». At the moment he is playing it as a magician. At one of the last levels he has to fight the line of archers. The only spell with which he can damage them is a fire ball. If Polycarp hits the i-th archer with his fire ball (they are numbered from left to right), the archer loses a health points. At the same time the spell damages the archers adjacent to the i-th (if any) — they lose b (1 ≤ b < a ≤ 10) health points each.
 *
 * As the extreme archers (i.e. archers numbered 1 and n) are very far, the fire ball cannot reach them. Polycarp can hit any other archer with his fire ball.
 *
 * The amount of health points for each archer is known. An archer will be killed when this amount is less than 0. What is the minimum amount of spells Polycarp can use to kill all the enemies?
 *
 * Polycarp can throw his fire ball into an archer if the latter is already killed.
 *
 * Input
 * The first line of the input contains three integers n, a, b (3 ≤ n ≤ 10; 1 ≤ b < a ≤ 10). The second line contains a sequence of n integers — h1, h2, ..., hn (1 ≤ hi ≤ 15), where hi is the amount of health points the i-th archer has.
 *
 * Output
 * In the first line print t — the required minimum amount of fire balls.
 *
 * In the second line print t numbers — indexes of the archers that Polycarp should hit to kill all the archers in t shots. All these numbers should be between 2 and n - 1. Separate numbers with spaces. If there are several solutions, output any of them. Print numbers in any order.
 *
 * Examples
 * input
 * 3 2 1
 * 2 2 2
 * output
 * 3
 * 2 2 2
 * input
 * 4 3 1
 * 1 4 1 1
 * output
 * 4
 * 2 2 3 3
 * */
#include <limits>
#include <iostream>

using namespace std;

int n, a, b;
int h[11], res[11], tmp[11];

int ans = numeric_limits<int>::max();

void dfs(int start, int cnt) {
    if (cnt >= ans) return;
    if (start == n) {
        ans = cnt;
        for (int i = 1; i <= n; i++) {
            res[i] = tmp[i];
        }
    } else {
        for (int i = 0; ; i++) {
            if (h[start-1] - i * b >= 0) continue; //left prior, cutting edges.
            if (i + cnt >= ans) break; //optimum
            if (start == n-1 && h[start+1] - i * b >= 0) continue; //cutting edges.

            h[start-1] -= i * b;
            h[start+1] -= i * b;
            h[start] -= i * a;

            tmp[start] = i;
            dfs(start+1, cnt+i);

            h[start-1] += i * b;
            h[start+1] += i * b;
            h[start] += i * a;

            if (h[start]-i*a<0 && h[start+1]-i*b<0) break;
        }
    }
}

int main() {

    cin >> n >>a >> b;
    for (int i = 1; i <= n; i++) {
        cin >> h[i];
    }
    dfs(2, 0);
    cout << ans << "\n";

    for (int i = 2; i < n; i++) {
        for (int j = 0; j < res[i];++j) {
            cout << i << " ";
        }
    }

    return 0;

}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <iostream>

/* A derived class can inherit from multiple base classes. */

class base1 {
  public:
    int x;
    int myfun() { return 1; }
    base1() { std::cout << "Constructing base 1" << std::endl; }
    ~base1() { std::cout << "destryoing base 1" << std::endl; }
};

class base2 {
  public:
    int y;
    /* int myfun() { return 2; }  If you would add this, myfun would
       will be ambiguous in derived class and programm wouldn't compile. */
    base2() { std::cout << "Constructing base 2" << std::endl; }
    ~base2() { std::cout << "Destryoing base 2" << std::endl; }
};

class derived : public base1, public base2 {
  public:
    derived() { std::cout << "Constructing derived." << std::endl; }
    ~derived() { std::cout << "Destryoing derived." << std::endl; }
};

int main(int argc, char *argv[])
{
    derived d;

    d.x = 7;  // Setting a member variable inherited from base 1.
    d.y = 8;  // Setting a member variable inherited from base 1.
    std::cout << d.myfun() << std::endl;

    return EXIT_SUCCESS;
}
<commit_msg>fixing a typo<commit_after>#include <cstdlib>
#include <iostream>

/* A derived class can inherit from multiple base classes. */

class base1 {
  public:
    int x;
    int myfun() { return 1; }
    base1() { std::cout << "Constructing base 1" << std::endl; }
    ~base1() { std::cout << "destryoing base 1" << std::endl; }
};

class base2 {
  public:
    int y;
    /* int myfun() { return 2; }  If you would add this, myfun would
       will be ambiguous in derived class and programm wouldn't compile. */
    base2() { std::cout << "Constructing base 2" << std::endl; }
    ~base2() { std::cout << "Destryoing base 2" << std::endl; }
};

class derived : public base1, public base2 {
  public:
    derived() { std::cout << "Constructing derived." << std::endl; }
    ~derived() { std::cout << "Destryoing derived." << std::endl; }
};

int main(int argc, char *argv[])
{
    derived d;

    d.x = 7;  // Setting a member variable inherited from base 1.
    d.y = 8;  // Setting a member variable inherited from base 2.
    std::cout << d.myfun() << std::endl;

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2019 The Open GEE Contributors
 *
 * 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 "StateUpdater.h"
#include "AssetVersionD.h"
#include "common/notify.h"

using namespace boost;
using namespace std;

// The depth_first_search function needs a way to map vertices to indexes. We
// store a unique index inside each vertex; the code below provides a way for
// boost to access them. These must be defined before including
// depth_first_search.hpp.
template <class Graph>
class InNodeVertexIndexMap {
  public:
    typedef readable_property_map_tag category;
    typedef size_t value_type;
    typedef value_type reference;
    typedef typename Graph::vertex_descriptor key_type;

    InNodeVertexIndexMap(const Graph & graph) : graph(graph) {};
    const Graph & graph;
};

namespace boost {
  template<>
  struct property_map<DependentStateTree, vertex_index_t> {
    typedef InNodeVertexIndexMap<DependentStateTree> const_type;
  };

  template<class Graph>
  InNodeVertexIndexMap<Graph> get(vertex_index_t, const Graph & graph) {
    return InNodeVertexIndexMap<Graph>(graph);
  }

  template<class Graph>
  typename InNodeVertexIndexMap<Graph>::value_type get(
      const InNodeVertexIndexMap<Graph> & map,
      typename InNodeVertexIndexMap<Graph>::key_type vertex) {
    return map.graph[vertex].index;
  }
}

#include <boost/graph/depth_first_search.hpp>

class StateUpdater::UnsupportedException : public std::runtime_error {
  public:
    UnsupportedException() : std::runtime_error("Unsupported operation") {}
};

class StateUpdater::SetStateVisitor : public default_dfs_visitor {
  private:
    StateUpdater * const updater;
    const AssetDefs::State newState;

    bool NeedComputeState(AssetDefs::State state) const {
      // these states are explicitly set and must be explicitly cleared
      return !(state & (AssetDefs::Bad |
                        AssetDefs::Offline |
                        AssetDefs::Canceled));
    }

    // Helper class for calculating state from inputs
    class InputStates {
      private:
        uint numinputs = 0;
        uint numgood = 0;
        uint numblocking = 0;
        uint numoffline = 0;
      public:
        void Add(AssetDefs::State inputState) {
          ++numinputs;
          if (inputState == AssetDefs::Succeeded) {
            ++numgood;
          } else if (inputState == AssetDefs::Offline) {
            ++numblocking;
            ++numoffline;
          } else if (inputState & (AssetDefs::Blocked |
                                   AssetDefs::Failed |
                                   AssetDefs::Canceled |
                                   AssetDefs::Bad)) {
            ++numblocking;
          }
        }
        void GetOutputs(AssetDefs::State & stateByInputs, bool & blockersAreOffline, uint32 & numWaitingFor) {
          if (numinputs == numgood) {
            stateByInputs = AssetDefs::Queued;
          } else if (numblocking) {
            stateByInputs = AssetDefs::Blocked;
          } else {
            stateByInputs = AssetDefs::Waiting;
          }

          blockersAreOffline = (numblocking == numoffline);

          if (stateByInputs == AssetDefs::Waiting) {
            numWaitingFor = (numinputs - numgood);
          } else {
            numWaitingFor = 0;
          }
        }
    };
    // Helper class for calculating state from children
    class ChildStates {
      private:
        uint numkids = 0;
        uint numgood = 0;
        uint numblocking = 0;
        uint numinprog = 0;
      public:
        void Add(AssetDefs::State childState) {
          ++numkids;
          if (childState == AssetDefs::Succeeded) {
            ++numgood;
          } else if (childState == AssetDefs::InProgress) {
            ++numinprog;
          } else if (childState & (AssetDefs::Failed   |
                                   AssetDefs::Blocked  |
                                   AssetDefs::Canceled |
                                   AssetDefs::Offline  |
                                   AssetDefs::Bad)) {
            ++numblocking;
          }
        }
        void GetOutputs(AssetDefs::State & stateByChildren) {
          if (numkids == numgood) {
            stateByChildren = AssetDefs::Succeeded;
          } else if (numblocking) {
            stateByChildren = AssetDefs::Blocked;
          } else if (numgood || numinprog) {
            stateByChildren = AssetDefs::InProgress;
          } else {
            stateByChildren = AssetDefs::Queued;
          }
        }
    };

    // Loops through the inputs and children of an asset and calculates
    // everything the asset verion needs to know to figure out its state. This
    // data will be passed to the asset version so it can calculate its own
    // state.
    void CalculateStateParameters(
        DependentStateTreeVertexDescriptor vertex,
        const DependentStateTree & tree,
        AssetDefs::State &stateByInputs,
        AssetDefs::State &stateByChildren,
        bool & blockersAreOffline,
        uint32 & numWaitingFor,
        bool & childOrInputStateChanged) const {
      InputStates inputStates;
      ChildStates childStates;

      childOrInputStateChanged = false;
      auto edgeIters = out_edges(vertex, tree);
      auto edgeBegin = edgeIters.first;
      auto edgeEnd = edgeIters.second;
      for (auto i = edgeBegin; i != edgeEnd; ++i) {
        DependencyType type = tree[*i].type;
        DependentStateTreeVertexDescriptor dep = target(*i, tree);
        AssetDefs::State depState = tree[dep].state;
        switch(type) {
          case INPUT:
            inputStates.Add(depState);
            childOrInputStateChanged = childOrInputStateChanged || tree[dep].stateChanged;
            break;
          case CHILD:
          case DEPENDENT_AND_CHILD:
            childStates.Add(depState);
            childOrInputStateChanged = childOrInputStateChanged || tree[dep].stateChanged;
            break;
          case DEPENDENT:
            // Dependents that are not also children are not considered when
            // calculating state.
            break;
        }
      }

      inputStates.GetOutputs(stateByInputs, blockersAreOffline, numWaitingFor);
      childStates.GetOutputs(stateByChildren);
    }

  public:
    SetStateVisitor(StateUpdater * updater, AssetDefs::State newState) :
        updater(updater), newState(newState) {}

    // This function is called after the DFS has completed for every vertex
    // below this one in the tree. Thus, we don't calculate the state for an
    // asset until we've calculated the state for all of its inputs and
    // children.
    virtual void finish_vertex(
        DependentStateTreeVertexDescriptor vertex,
        const DependentStateTree & tree) const {
      if (!tree[vertex].recalcState) return;
      SharedString name = tree[vertex].name;
      notify(NFY_PROGRESS, "Calculating state for '%s'", name.toString().c_str());

      // Set the state for assets in the dependent tree. Don't send
      // notifications because we'll set the state again below.
      if (tree[vertex].inDepTree) {
        updater->SetState(vertex, newState, false);
      }

      // For all assets (including parents and listeners) update the state
      // based on the state of inputs and children.
      if (NeedComputeState(tree[vertex].state)) {
        AssetDefs::State stateByInputs;
        AssetDefs::State stateByChildren;
        bool blockersAreOffline;
        uint32 numWaitingFor;
        bool childOrInputStateChanged;
        CalculateStateParameters(
              vertex, tree, stateByInputs, stateByChildren,
              blockersAreOffline, numWaitingFor, childOrInputStateChanged);
        if (tree[vertex].stateChanged || childOrInputStateChanged) {
          AssetDefs::State calculatedState;
          // Run this in a separate block so that the asset version is released
          // before we try to update it.
          {
            auto version = updater->storageManager->Get(name);
            if (!version) {
              // This shoud never happen - we had to successfully load the asset
              // previously to get it into the tree.
              notify(NFY_WARN, "Could not load asset '%s' to recalculate state.",
                     name.toString().c_str());
              return;
            }
            calculatedState = version->CalcStateByInputsAndChildren(
                  stateByInputs, stateByChildren, blockersAreOffline, numWaitingFor);
          }
          // Set the state and send notifications.
          updater->SetState(vertex, calculatedState, true);
        }
      }
    }
};

void StateUpdater::SetStateForRefAndDependents(
    const SharedString & ref,
    AssetDefs::State newState,
    function<bool(AssetDefs::State)> updateStatePredicate) {
  try {
    SharedString verref = AssetVersionImpl::Key(ref);
    tree = BuildDependentStateTree(verref, updateStatePredicate, storageManager);
    depth_first_search(tree, visitor(SetStateVisitor(this, newState)));
  }
  catch (UnsupportedException) {
    // This is intended as a temporary condition that will no longer be needed
    // when all operations have been converted to use the state updater for
    // propagating state changes.
    notify(NFY_INFO, "Unsupported condition encountered in state updater. "
           "Reverting to legacy state propagation.");
  }
}

void StateUpdater::SetState(
    DependentStateTreeVertexDescriptor vertex,
    AssetDefs::State newState,
    bool finalStateChange) {
  SharedString name = tree[vertex].name;
  AssetDefs::State oldState = tree[vertex].state;
  if (newState != oldState) {
    notify(NFY_PROGRESS, "Setting state of '%s' from '%s' to '%s'",
           name.toString().c_str(), ToString(oldState).c_str(), ToString(newState).c_str());
    auto version = storageManager->GetMutable(name);
    if (version) {
      SetVersionStateAndRunHandlers(name, version, oldState, newState, finalStateChange);

      // Get the new state directly from the asset version since it may be
      // different from the passed-in state
      tree[vertex].state = version->state;
      tree[vertex].stateChanged = true;

      if (finalStateChange) {
        SendStateChangeNotification(name, version->state);
      }
    }
    else {
      // This shoud never happen - we had to successfully load the asset
      // previously to get it into the tree.
      notify(NFY_WARN, "Could not load asset '%s' to set state.",
             name.toString().c_str());
    }
  }
}

void StateUpdater::SetVersionStateAndRunHandlers(
    const SharedString & name,
    AssetHandle<AssetVersionImpl> & version,
    AssetDefs::State oldState,
    AssetDefs::State newState,
    bool finalStateChange) {
  // OnStateChange can return a new state that we need to transition to, so we
  // may have to change the state repeatedly.
  do {
    version->state = newState;
    // Don't run handlers if this is a temporary state change.
    if (finalStateChange) {
      AssetDefs::State nextState = AssetDefs::Failed;
      try {
        // This will take care of stopping any running tasks, etc.
        bool hasChildrenBefore = !version->children.empty();
        nextState = version->OnStateChange(newState, oldState);
        bool hasChildrenAfter = !version->children.empty();
        if (!hasChildrenBefore && hasChildrenAfter) {
          // OnStateChange can call DelayedBuildChildren, which creates new
          // children for this asset. This code is not yet able to handle that
          // case, so we let OnStateChange perform the legacy state propagation
          // and abandon this operation.
          throw UnsupportedException();
        }
      } catch (const StateChangeException &e) {
        notify(NFY_WARN, "Exception during %s: %s : %s",
               e.location.c_str(), name.toString().c_str(), e.what());
        AssetVersionImplD::WriteFatalLogfile(name, e.location, e.what());
      } catch (const std::exception &e) {
        notify(NFY_WARN, "Exception during OnStateChange: %s", e.what());
      } catch (...) {
        notify(NFY_WARN, "Unknown exception during OnStateChange");
      }
      oldState = newState;
      newState = nextState;
    }
  } while(version->state != newState);
}

void StateUpdater::SendStateChangeNotification(
    const SharedString & name,
    AssetDefs::State state) {
  notify(NFY_VERBOSE, "Calling theAssetManager.NotifyVersionStateChange(%s, %s)",
         name.toString().c_str(),
         ToString(state).c_str());
  assetManager->NotifyVersionStateChange(name, state);
}
<commit_msg>Clarify comments<commit_after>/*
 * Copyright 2019 The Open GEE Contributors
 *
 * 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 "StateUpdater.h"
#include "AssetVersionD.h"
#include "common/notify.h"

using namespace boost;
using namespace std;

// The depth_first_search function needs a way to map vertices to indexes. We
// store a unique index inside each vertex; the code below provides a way for
// boost to access them. These must be defined before including
// depth_first_search.hpp.
template <class Graph>
class InNodeVertexIndexMap {
  public:
    typedef readable_property_map_tag category;
    typedef size_t value_type;
    typedef value_type reference;
    typedef typename Graph::vertex_descriptor key_type;

    InNodeVertexIndexMap(const Graph & graph) : graph(graph) {};
    const Graph & graph;
};

namespace boost {
  template<>
  struct property_map<DependentStateTree, vertex_index_t> {
    typedef InNodeVertexIndexMap<DependentStateTree> const_type;
  };

  template<class Graph>
  InNodeVertexIndexMap<Graph> get(vertex_index_t, const Graph & graph) {
    return InNodeVertexIndexMap<Graph>(graph);
  }

  template<class Graph>
  typename InNodeVertexIndexMap<Graph>::value_type get(
      const InNodeVertexIndexMap<Graph> & map,
      typename InNodeVertexIndexMap<Graph>::key_type vertex) {
    return map.graph[vertex].index;
  }
}

#include <boost/graph/depth_first_search.hpp>

class StateUpdater::UnsupportedException : public std::runtime_error {
  public:
    UnsupportedException() : std::runtime_error("Unsupported operation") {}
};

class StateUpdater::SetStateVisitor : public default_dfs_visitor {
  private:
    StateUpdater * const updater;
    const AssetDefs::State newState;

    bool NeedComputeState(AssetDefs::State state) const {
      // these states are explicitly set and must be explicitly cleared
      return !(state & (AssetDefs::Bad |
                        AssetDefs::Offline |
                        AssetDefs::Canceled));
    }

    // Helper class for calculating state from inputs
    class InputStates {
      private:
        uint numinputs = 0;
        uint numgood = 0;
        uint numblocking = 0;
        uint numoffline = 0;
      public:
        void Add(AssetDefs::State inputState) {
          ++numinputs;
          if (inputState == AssetDefs::Succeeded) {
            ++numgood;
          } else if (inputState == AssetDefs::Offline) {
            ++numblocking;
            ++numoffline;
          } else if (inputState & (AssetDefs::Blocked |
                                   AssetDefs::Failed |
                                   AssetDefs::Canceled |
                                   AssetDefs::Bad)) {
            ++numblocking;
          }
        }
        void GetOutputs(AssetDefs::State & stateByInputs, bool & blockersAreOffline, uint32 & numWaitingFor) {
          if (numinputs == numgood) {
            stateByInputs = AssetDefs::Queued;
          } else if (numblocking) {
            stateByInputs = AssetDefs::Blocked;
          } else {
            stateByInputs = AssetDefs::Waiting;
          }

          blockersAreOffline = (numblocking == numoffline);

          if (stateByInputs == AssetDefs::Waiting) {
            numWaitingFor = (numinputs - numgood);
          } else {
            numWaitingFor = 0;
          }
        }
    };
    // Helper class for calculating state from children
    class ChildStates {
      private:
        uint numkids = 0;
        uint numgood = 0;
        uint numblocking = 0;
        uint numinprog = 0;
      public:
        void Add(AssetDefs::State childState) {
          ++numkids;
          if (childState == AssetDefs::Succeeded) {
            ++numgood;
          } else if (childState == AssetDefs::InProgress) {
            ++numinprog;
          } else if (childState & (AssetDefs::Failed   |
                                   AssetDefs::Blocked  |
                                   AssetDefs::Canceled |
                                   AssetDefs::Offline  |
                                   AssetDefs::Bad)) {
            ++numblocking;
          }
        }
        void GetOutputs(AssetDefs::State & stateByChildren) {
          if (numkids == numgood) {
            stateByChildren = AssetDefs::Succeeded;
          } else if (numblocking) {
            stateByChildren = AssetDefs::Blocked;
          } else if (numgood || numinprog) {
            stateByChildren = AssetDefs::InProgress;
          } else {
            stateByChildren = AssetDefs::Queued;
          }
        }
    };

    // Loops through the inputs and children of an asset and calculates
    // everything the asset verion needs to know to figure out its state. This
    // data will be passed to the asset version so it can calculate its own
    // state.
    void CalculateStateParameters(
        DependentStateTreeVertexDescriptor vertex,
        const DependentStateTree & tree,
        AssetDefs::State &stateByInputs,
        AssetDefs::State &stateByChildren,
        bool & blockersAreOffline,
        uint32 & numWaitingFor,
        bool & childOrInputStateChanged) const {
      InputStates inputStates;
      ChildStates childStates;

      childOrInputStateChanged = false;
      auto edgeIters = out_edges(vertex, tree);
      auto edgeBegin = edgeIters.first;
      auto edgeEnd = edgeIters.second;
      for (auto i = edgeBegin; i != edgeEnd; ++i) {
        DependencyType type = tree[*i].type;
        DependentStateTreeVertexDescriptor dep = target(*i, tree);
        AssetDefs::State depState = tree[dep].state;
        switch(type) {
          case INPUT:
            inputStates.Add(depState);
            childOrInputStateChanged = childOrInputStateChanged || tree[dep].stateChanged;
            break;
          case CHILD:
          case DEPENDENT_AND_CHILD:
            childStates.Add(depState);
            childOrInputStateChanged = childOrInputStateChanged || tree[dep].stateChanged;
            break;
          case DEPENDENT:
            // Dependents that are not also children are not considered when
            // calculating state.
            break;
        }
      }

      inputStates.GetOutputs(stateByInputs, blockersAreOffline, numWaitingFor);
      childStates.GetOutputs(stateByChildren);
    }

  public:
    SetStateVisitor(StateUpdater * updater, AssetDefs::State newState) :
        updater(updater), newState(newState) {}

    // This function is called after the DFS has completed for every vertex
    // below this one in the tree. Thus, we don't calculate the state for an
    // asset until we've calculated the state for all of its inputs and
    // children.
    virtual void finish_vertex(
        DependentStateTreeVertexDescriptor vertex,
        const DependentStateTree & tree) const {
      if (!tree[vertex].recalcState) return;
      SharedString name = tree[vertex].name;
      notify(NFY_PROGRESS, "Calculating state for '%s'", name.toString().c_str());

      // Set the state for assets in the dependent tree. "false" means we'll
      // set the state again below.
      if (tree[vertex].inDepTree) {
        updater->SetState(vertex, newState, false);
      }

      // For all assets (including parents and listeners) update the state
      // based on the state of inputs and children.
      if (NeedComputeState(tree[vertex].state)) {
        AssetDefs::State stateByInputs;
        AssetDefs::State stateByChildren;
        bool blockersAreOffline;
        uint32 numWaitingFor;
        bool childOrInputStateChanged;
        CalculateStateParameters(
              vertex, tree, stateByInputs, stateByChildren,
              blockersAreOffline, numWaitingFor, childOrInputStateChanged);
        if (tree[vertex].stateChanged || childOrInputStateChanged) {
          AssetDefs::State calculatedState;
          // Run this in a separate block so that the asset version is released
          // before we try to update it.
          {
            auto version = updater->storageManager->Get(name);
            if (!version) {
              // This shoud never happen - we had to successfully load the asset
              // previously to get it into the tree.
              notify(NFY_WARN, "Could not load asset '%s' to recalculate state.",
                     name.toString().c_str());
              return;
            }
            calculatedState = version->CalcStateByInputsAndChildren(
                  stateByInputs, stateByChildren, blockersAreOffline, numWaitingFor);
          }
          // Set the state. "true" means we're done changing this asset's state.
          updater->SetState(vertex, calculatedState, true);
        }
      }
    }
};

void StateUpdater::SetStateForRefAndDependents(
    const SharedString & ref,
    AssetDefs::State newState,
    function<bool(AssetDefs::State)> updateStatePredicate) {
  try {
    SharedString verref = AssetVersionImpl::Key(ref);
    tree = BuildDependentStateTree(verref, updateStatePredicate, storageManager);
    depth_first_search(tree, visitor(SetStateVisitor(this, newState)));
  }
  catch (UnsupportedException) {
    // This is intended as a temporary condition that will no longer be needed
    // when all operations have been converted to use the state updater for
    // propagating state changes.
    notify(NFY_INFO, "Unsupported condition encountered in state updater. "
           "Reverting to legacy state propagation.");
  }
}

void StateUpdater::SetState(
    DependentStateTreeVertexDescriptor vertex,
    AssetDefs::State newState,
    bool finalStateChange) {
  SharedString name = tree[vertex].name;
  AssetDefs::State oldState = tree[vertex].state;
  if (newState != oldState) {
    notify(NFY_PROGRESS, "Setting state of '%s' from '%s' to '%s'",
           name.toString().c_str(), ToString(oldState).c_str(), ToString(newState).c_str());
    auto version = storageManager->GetMutable(name);
    if (version) {
      SetVersionStateAndRunHandlers(name, version, oldState, newState, finalStateChange);

      // Get the new state directly from the asset version since it may be
      // different from the passed-in state
      tree[vertex].state = version->state;
      tree[vertex].stateChanged = true;

      if (finalStateChange) {
        SendStateChangeNotification(name, version->state);
      }
    }
    else {
      // This shoud never happen - we had to successfully load the asset
      // previously to get it into the tree.
      notify(NFY_WARN, "Could not load asset '%s' to set state.",
             name.toString().c_str());
    }
  }
}

void StateUpdater::SetVersionStateAndRunHandlers(
    const SharedString & name,
    AssetHandle<AssetVersionImpl> & version,
    AssetDefs::State oldState,
    AssetDefs::State newState,
    bool finalStateChange) {
  // OnStateChange can return a new state that we need to transition to, so we
  // may have to change the state repeatedly.
  do {
    version->state = newState;
    // Don't run handlers if this is a temporary state change.
    if (finalStateChange) {
      AssetDefs::State nextState = AssetDefs::Failed;
      try {
        // This will take care of stopping any running tasks, etc.
        bool hasChildrenBefore = !version->children.empty();
        nextState = version->OnStateChange(newState, oldState);
        bool hasChildrenAfter = !version->children.empty();
        if (!hasChildrenBefore && hasChildrenAfter) {
          // OnStateChange can call DelayedBuildChildren, which creates new
          // children for this asset. This code is not yet able to handle that
          // case, so we let OnStateChange perform the legacy state propagation
          // and abandon this operation.
          throw UnsupportedException();
        }
      } catch (const StateChangeException &e) {
        notify(NFY_WARN, "Exception during %s: %s : %s",
               e.location.c_str(), name.toString().c_str(), e.what());
        AssetVersionImplD::WriteFatalLogfile(name, e.location, e.what());
      } catch (const std::exception &e) {
        notify(NFY_WARN, "Exception during OnStateChange: %s", e.what());
      } catch (...) {
        notify(NFY_WARN, "Unknown exception during OnStateChange");
      }
      oldState = newState;
      newState = nextState;
    }
  } while(version->state != newState);
}

void StateUpdater::SendStateChangeNotification(
    const SharedString & name,
    AssetDefs::State state) {
  notify(NFY_VERBOSE, "Calling theAssetManager.NotifyVersionStateChange(%s, %s)",
         name.toString().c_str(),
         ToString(state).c_str());
  assetManager->NotifyVersionStateChange(name, state);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: profiler.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 00:35:47 $
 *
 *  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_automation.hxx"

#ifndef _TIME_HXX //autogen
#include <tools/time.hxx>
#endif
#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif
#ifndef _UNOTOOLS_LOCALEDATAWRAPPER_HXX
#include <unotools/localedatawrapper.hxx>
#endif
#ifndef _SV_SVAPP_HXX //autogen
#include <vcl/svapp.hxx>
#endif
#ifndef _BASIC_TTRESHLP_HXX
#include <basic/ttstrhlp.hxx>
#endif

#include "profiler.hxx"

TTProfiler::TTProfiler()
: mpStart( NULL )
, mpEnd( NULL )
, bIsProfileIntervalStarted( FALSE )
, bIsProfilingPerCommand( FALSE )
, bIsPartitioning( FALSE )
, bIsAutoProfiling( FALSE )
, pSysDepStatic( NULL )
{
    InitSysdepProfiler();
    mpStart = new ProfileSnapshot;
    mpStart->pSysdepProfileSnapshot = NewSysdepSnapshotData();
    mpEnd = new ProfileSnapshot;
    mpEnd->pSysdepProfileSnapshot = NewSysdepSnapshotData();
    StartProfileInterval();
}

TTProfiler::~TTProfiler()
{
    if ( IsAutoProfiling() )
        StopAutoProfiling();
    if ( mpStart )
    {
        if ( mpStart->pSysdepProfileSnapshot )
            DeleteSysdepSnapshotData( mpStart->pSysdepProfileSnapshot );
        delete mpStart;
        mpStart = NULL;
    }
    if ( mpEnd )
    {
        if ( mpEnd->pSysdepProfileSnapshot )
            DeleteSysdepSnapshotData( mpEnd->pSysdepProfileSnapshot );
        delete mpEnd;
        mpEnd = NULL;
    }
    DeinitSysdepProfiler();
}

String TTProfiler::GetProfileHeader()
{
    UniString aReturn;
    aReturn += '\n';
    if ( !IsAutoProfiling() )
        aReturn.AppendAscii("Befehl").Append(TabString(36));

    aReturn.AppendAscii("   Zeitdauer");
    aReturn.AppendAscii("  Ticks in %");
    aReturn.Append( GetSysdepProfileHeader() );
    aReturn.AppendAscii("\n");
    return aReturn;
}

void TTProfiler::StartProfileInterval( BOOL bReadAnyway )
{
    if ( !bIsProfileIntervalStarted || bReadAnyway )
    {
        GetProfileSnapshot( mpStart );
        GetSysdepProfileSnapshot( mpStart->pSysdepProfileSnapshot, PROFILE_START );
        bIsProfileIntervalStarted = TRUE;
    }
}

String TTProfiler::GetProfileLine( ProfileSnapshot *pStart, ProfileSnapshot *pEnd )
{
    String aProfileString;

    aProfileString += Pad(GetpApp()->GetAppLocaleDataWrapper().getDuration( DIFF( pStart, pEnd, aTime) , TRUE, TRUE ), 12);

    ULONG nProcessTicks = DIFF( pStart, pEnd, nProcessTicks );
    ULONG nSystemTicks = DIFF( pStart, pEnd, nSystemTicks );
    if ( nSystemTicks )
    {
        aProfileString += Pad(UniString::CreateFromInt32( (100 * nProcessTicks) / nSystemTicks ), 11);
        aProfileString += '%';
    }
    else
        aProfileString += Pad(CUniString("??  "), 12);

    return aProfileString;
}

String TTProfiler::GetProfileLine( String &aPrefix )
{
    String aProfileString;
    if ( IsProfilingPerCommand() || IsAutoProfiling() )
    {
        aProfileString = aPrefix;
        aProfileString += TabString(35);

        aProfileString += GetProfileLine( mpStart, mpEnd );
        aProfileString += GetSysdepProfileLine( mpStart->pSysdepProfileSnapshot, mpEnd->pSysdepProfileSnapshot );
        aProfileString += '\n';
    }

    return aProfileString;
}

void TTProfiler::EndProfileInterval()
{
    GetProfileSnapshot( mpEnd );
    GetSysdepProfileSnapshot( mpEnd->pSysdepProfileSnapshot, PROFILE_END );
    bIsProfileIntervalStarted = FALSE;
}

void TTProfiler::GetProfileSnapshot( ProfileSnapshot *pProfileSnapshot )
{
    pProfileSnapshot->aTime = Time();
    pProfileSnapshot->nProcessTicks = Time::GetProcessTicks();
    pProfileSnapshot->nSystemTicks = Time::GetSystemTicks();
}

void TTProfiler::StartProfilingPerCommand()     // Jeden Befehl mitschneiden
{
    bIsProfilingPerCommand = TRUE;
}

void TTProfiler::StopProfilingPerCommand()
{
    bIsProfilingPerCommand = FALSE;
}

void TTProfiler::StartPartitioning()
{
    bIsPartitioning = TRUE;
}

void TTProfiler::StopPartitioning()
{
    bIsPartitioning = TRUE;
}

ULONG TTProfiler::GetPartitioningTime()
{
    return DIFF( mpStart, mpEnd, nSystemTicks );
}

void TTProfiler::StartAutoProfiling( ULONG nMSec )
{
    if ( !bIsAutoProfiling )
    {
        pAutoStart = new ProfileSnapshot;
        pAutoStart->pSysdepProfileSnapshot = NewSysdepSnapshotData();
        pAutoEnd = new ProfileSnapshot;
        pAutoEnd->pSysdepProfileSnapshot = NewSysdepSnapshotData();
        GetProfileSnapshot( pAutoStart );
        GetSysdepProfileSnapshot( pAutoStart->pSysdepProfileSnapshot, PROFILE_START );
        SetTimeout( nMSec );
        bIsAutoProfiling = TRUE;
        Start();
    }

}

void TTProfiler::Timeout()
{
    GetProfileSnapshot( pAutoEnd );
    GetSysdepProfileSnapshot( pAutoEnd->pSysdepProfileSnapshot, PROFILE_END );
    String aLine;

    aLine += GetProfileLine( pAutoStart, pAutoEnd );
    aLine += GetSysdepProfileLine( pAutoStart->pSysdepProfileSnapshot, pAutoEnd->pSysdepProfileSnapshot );
    aLine += '\n';

    aAutoProfileBuffer += aLine;

    ProfileSnapshot *pTemp = pAutoStart;        // Tauschen, so da jetziges Ende nchsten Start wird
    pAutoStart = pAutoEnd;
    pAutoEnd = pTemp;

    Start();    // Timer neu starten
}

String TTProfiler::GetAutoProfiling()
{
    String aTemp(aAutoProfileBuffer);
    aAutoProfileBuffer.Erase();
    return aTemp;
}

void TTProfiler::StopAutoProfiling()
{
    if ( bIsAutoProfiling )
    {
        Stop();
        bIsAutoProfiling = FALSE;
    }
}

//String TTProfiler::Hex( ULONG nNr )
String TTProfiler::Dec( ULONG nNr )
{
    String aRet(UniString::CreateFromInt32(nNr));
    if ( nNr < 100 )
    {
        aRet = Pad( aRet, 3);
        aRet.SearchAndReplaceAll(' ','0');
    }
    aRet.Insert( ',', aRet.Len() - 2 );
    return aRet;
}

String TTProfiler::Pad( const String aS, xub_StrLen nLen )
{
    if ( nLen > aS.Len() )
        return UniString().Fill( nLen - aS.Len() ).Append( aS );
    else
        return CUniString(" ").Append( aS );
}

<commit_msg>INTEGRATION: CWS changefileheader (1.5.86); FILE MERGED 2008/04/01 15:00:02 thb 1.5.86.2: #i85898# Stripping all external header guards 2008/03/28 16:03:38 rt 1.5.86.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: profiler.cxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

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

#include <tools/time.hxx>
#include <tools/string.hxx>
#include <unotools/localedatawrapper.hxx>
#include <vcl/svapp.hxx>
#ifndef _BASIC_TTRESHLP_HXX
#include <basic/ttstrhlp.hxx>
#endif

#include "profiler.hxx"

TTProfiler::TTProfiler()
: mpStart( NULL )
, mpEnd( NULL )
, bIsProfileIntervalStarted( FALSE )
, bIsProfilingPerCommand( FALSE )
, bIsPartitioning( FALSE )
, bIsAutoProfiling( FALSE )
, pSysDepStatic( NULL )
{
    InitSysdepProfiler();
    mpStart = new ProfileSnapshot;
    mpStart->pSysdepProfileSnapshot = NewSysdepSnapshotData();
    mpEnd = new ProfileSnapshot;
    mpEnd->pSysdepProfileSnapshot = NewSysdepSnapshotData();
    StartProfileInterval();
}

TTProfiler::~TTProfiler()
{
    if ( IsAutoProfiling() )
        StopAutoProfiling();
    if ( mpStart )
    {
        if ( mpStart->pSysdepProfileSnapshot )
            DeleteSysdepSnapshotData( mpStart->pSysdepProfileSnapshot );
        delete mpStart;
        mpStart = NULL;
    }
    if ( mpEnd )
    {
        if ( mpEnd->pSysdepProfileSnapshot )
            DeleteSysdepSnapshotData( mpEnd->pSysdepProfileSnapshot );
        delete mpEnd;
        mpEnd = NULL;
    }
    DeinitSysdepProfiler();
}

String TTProfiler::GetProfileHeader()
{
    UniString aReturn;
    aReturn += '\n';
    if ( !IsAutoProfiling() )
        aReturn.AppendAscii("Befehl").Append(TabString(36));

    aReturn.AppendAscii("   Zeitdauer");
    aReturn.AppendAscii("  Ticks in %");
    aReturn.Append( GetSysdepProfileHeader() );
    aReturn.AppendAscii("\n");
    return aReturn;
}

void TTProfiler::StartProfileInterval( BOOL bReadAnyway )
{
    if ( !bIsProfileIntervalStarted || bReadAnyway )
    {
        GetProfileSnapshot( mpStart );
        GetSysdepProfileSnapshot( mpStart->pSysdepProfileSnapshot, PROFILE_START );
        bIsProfileIntervalStarted = TRUE;
    }
}

String TTProfiler::GetProfileLine( ProfileSnapshot *pStart, ProfileSnapshot *pEnd )
{
    String aProfileString;

    aProfileString += Pad(GetpApp()->GetAppLocaleDataWrapper().getDuration( DIFF( pStart, pEnd, aTime) , TRUE, TRUE ), 12);

    ULONG nProcessTicks = DIFF( pStart, pEnd, nProcessTicks );
    ULONG nSystemTicks = DIFF( pStart, pEnd, nSystemTicks );
    if ( nSystemTicks )
    {
        aProfileString += Pad(UniString::CreateFromInt32( (100 * nProcessTicks) / nSystemTicks ), 11);
        aProfileString += '%';
    }
    else
        aProfileString += Pad(CUniString("??  "), 12);

    return aProfileString;
}

String TTProfiler::GetProfileLine( String &aPrefix )
{
    String aProfileString;
    if ( IsProfilingPerCommand() || IsAutoProfiling() )
    {
        aProfileString = aPrefix;
        aProfileString += TabString(35);

        aProfileString += GetProfileLine( mpStart, mpEnd );
        aProfileString += GetSysdepProfileLine( mpStart->pSysdepProfileSnapshot, mpEnd->pSysdepProfileSnapshot );
        aProfileString += '\n';
    }

    return aProfileString;
}

void TTProfiler::EndProfileInterval()
{
    GetProfileSnapshot( mpEnd );
    GetSysdepProfileSnapshot( mpEnd->pSysdepProfileSnapshot, PROFILE_END );
    bIsProfileIntervalStarted = FALSE;
}

void TTProfiler::GetProfileSnapshot( ProfileSnapshot *pProfileSnapshot )
{
    pProfileSnapshot->aTime = Time();
    pProfileSnapshot->nProcessTicks = Time::GetProcessTicks();
    pProfileSnapshot->nSystemTicks = Time::GetSystemTicks();
}

void TTProfiler::StartProfilingPerCommand()     // Jeden Befehl mitschneiden
{
    bIsProfilingPerCommand = TRUE;
}

void TTProfiler::StopProfilingPerCommand()
{
    bIsProfilingPerCommand = FALSE;
}

void TTProfiler::StartPartitioning()
{
    bIsPartitioning = TRUE;
}

void TTProfiler::StopPartitioning()
{
    bIsPartitioning = TRUE;
}

ULONG TTProfiler::GetPartitioningTime()
{
    return DIFF( mpStart, mpEnd, nSystemTicks );
}

void TTProfiler::StartAutoProfiling( ULONG nMSec )
{
    if ( !bIsAutoProfiling )
    {
        pAutoStart = new ProfileSnapshot;
        pAutoStart->pSysdepProfileSnapshot = NewSysdepSnapshotData();
        pAutoEnd = new ProfileSnapshot;
        pAutoEnd->pSysdepProfileSnapshot = NewSysdepSnapshotData();
        GetProfileSnapshot( pAutoStart );
        GetSysdepProfileSnapshot( pAutoStart->pSysdepProfileSnapshot, PROFILE_START );
        SetTimeout( nMSec );
        bIsAutoProfiling = TRUE;
        Start();
    }

}

void TTProfiler::Timeout()
{
    GetProfileSnapshot( pAutoEnd );
    GetSysdepProfileSnapshot( pAutoEnd->pSysdepProfileSnapshot, PROFILE_END );
    String aLine;

    aLine += GetProfileLine( pAutoStart, pAutoEnd );
    aLine += GetSysdepProfileLine( pAutoStart->pSysdepProfileSnapshot, pAutoEnd->pSysdepProfileSnapshot );
    aLine += '\n';

    aAutoProfileBuffer += aLine;

    ProfileSnapshot *pTemp = pAutoStart;        // Tauschen, so da jetziges Ende nchsten Start wird
    pAutoStart = pAutoEnd;
    pAutoEnd = pTemp;

    Start();    // Timer neu starten
}

String TTProfiler::GetAutoProfiling()
{
    String aTemp(aAutoProfileBuffer);
    aAutoProfileBuffer.Erase();
    return aTemp;
}

void TTProfiler::StopAutoProfiling()
{
    if ( bIsAutoProfiling )
    {
        Stop();
        bIsAutoProfiling = FALSE;
    }
}

//String TTProfiler::Hex( ULONG nNr )
String TTProfiler::Dec( ULONG nNr )
{
    String aRet(UniString::CreateFromInt32(nNr));
    if ( nNr < 100 )
    {
        aRet = Pad( aRet, 3);
        aRet.SearchAndReplaceAll(' ','0');
    }
    aRet.Insert( ',', aRet.Len() - 2 );
    return aRet;
}

String TTProfiler::Pad( const String aS, xub_StrLen nLen )
{
    if ( nLen > aS.Len() )
        return UniString().Fill( nLen - aS.Len() ).Append( aS );
    else
        return CUniString(" ").Append( aS );
}

<|endoftext|>


<commit_before>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "config.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/none.hpp>

#include <algorithm>
#include <sstream>

/**
 * \file config.cxx
 *
 * \brief Implementation of \link vistk::config configuration\endlink in the pipeline.
 */

namespace vistk
{

config::key_t const config::block_sep = key_t(":");
config::key_t const config::global_value = key_t("_global");

static bool does_not_begin_with(config::key_t const& key, config::key_t const& name);
static config::key_t strip_block_name(config::key_t const& key);

config_t
config
::empty_config(key_t const& name)
{
  return config_t(new config(name, config_t()));
}

config
::~config()
{
}

config_t
config
::subblock(key_t const& key) const
{
  config_t conf = empty_config(key);

  BOOST_FOREACH (key_t const& key_name, available_values())
  {
    if (does_not_begin_with(key_name, key))
    {
      continue;
    }

    key_t const stripped_key_name = strip_block_name(key_name);

    conf->set_value(stripped_key_name, get_value(key_name));
  }

  return conf;
}

config_t
config
::subblock_view(key_t const& key)
{
  return config_t(new config(key, shared_from_this()));
}

void
config
::set_value(key_t const& key, value_t const& value)
{
  if (m_parent)
  {
    m_parent->set_value(m_name + block_sep + key, value);
  }
  else
  {
    if (is_read_only(key))
    {
      throw set_on_read_only_value_exception(key, get_value<value_t>(key, value_t()), value);
    }

    m_store[key] = value;
  }
}

void
config
::unset_value(key_t const& key)
{
  if (m_parent)
  {
    m_parent->unset_value(m_name + block_sep + key);
  }
  else
  {
    if (is_read_only(key))
    {
      throw unset_on_read_only_value_exception(key, get_value<value_t>(key, value_t()));
    }

    m_store.erase(key);
  }
}

bool
config
::is_read_only(key_t const& key) const
{
  ro_list_t::iterator i = m_ro_list.find(key);

  return (i != m_ro_list.end());
}

void
config
::mark_read_only(key_t const& key)
{
  m_ro_list.insert(key);
}

void
config
::merge_config(config_t conf)
{
  BOOST_FOREACH (store_t::value_type const& value, conf->m_store)
  {
    set_value(value.first, value.second);
  }
}

config::keys_t
config
::available_values() const
{
  keys_t keys;

  if (m_parent)
  {
    keys = m_parent->available_values();

    keys_t::iterator const i = std::remove_if(keys.begin(), keys.end(), boost::bind(does_not_begin_with, _1, m_name));

    keys.erase(i, keys.end());

    std::for_each(keys.begin(), keys.end(), strip_block_name);
  }
  else
  {
    BOOST_FOREACH (store_t::value_type const& value, m_store)
    {
      keys.push_back(value.first);
    }
  }

  return keys;
}

bool
config
::has_value(key_t const& key) const
{
  if (m_parent)
  {
    return m_parent->has_value(m_name + block_sep + key);
  }

  return (m_store.find(key) != m_store.end());
}

config
::config(key_t const& name, config_t parent)
  : m_parent(parent)
  , m_name(name)
  , m_store()
{
}

boost::optional<config::value_t>
config
::find_value(key_t const& key) const
{
  if (!has_value(key))
  {
    return boost::none;
  }

  return get_value(key);
}

config::value_t
config
::get_value(key_t const& key) const
{
  if (m_parent)
  {
    return m_parent->get_value(m_name + block_sep + key);
  }

  store_t::const_iterator i = m_store.find(key);

  if (i == m_store.end())
  {
    return value_t();
  }

  return i->second;
}

bad_configuration_cast
::bad_configuration_cast(char const* reason) throw()
  : configuration_exception()
{
  m_what = reason;
}

bad_configuration_cast
::~bad_configuration_cast() throw()
{
}

no_such_configuration_value_exception
::no_such_configuration_value_exception(config::key_t const& key) throw()
  : configuration_exception()
  , m_key(key)
{
  std::ostringstream sstr;

  sstr << "There is no configuration value with the key "
          "\'" << m_key << "\'.";

  m_what = sstr.str();
}

no_such_configuration_value_exception
::~no_such_configuration_value_exception() throw()
{
}

bad_configuration_cast_exception
::bad_configuration_cast_exception(config::key_t const& key, config::value_t const& value, char const* type, char const* reason) throw()
  : configuration_exception()
  , m_key(key)
  , m_value(value)
  , m_type(type)
  , m_reason(reason)
{
  std::ostringstream sstr;

  sstr << "Failed to cast key \'" << m_key << "\' "
          "with value \'" << m_value << "\' as "
          "a \'" << m_type << "\': " << m_reason << ".";

  m_what = sstr.str();
}

bad_configuration_cast_exception
::~bad_configuration_cast_exception() throw()
{
}

set_on_read_only_value_exception
::set_on_read_only_value_exception(config::key_t const& key, config::value_t const& value, config::value_t const& new_value) throw()
  : configuration_exception()
  , m_key(key)
  , m_value(value)
  , m_new_value(new_value)
{
  std::ostringstream sstr;

  sstr << "The key \'" << m_key << "\' "
          "was marked as read-only with the value "
          "\'" << m_value << "\' was attempted to be "
          "set to \'" << m_key << "\'.";

  m_what = sstr.str();
}

set_on_read_only_value_exception
::~set_on_read_only_value_exception() throw()
{
}

unset_on_read_only_value_exception
::unset_on_read_only_value_exception(config::key_t const& key, config::value_t const& value) throw()
  : configuration_exception()
  , m_key(key)
  , m_value(value)
{
  std::ostringstream sstr;

  sstr << "The key \'" << m_key << "\' "
          "was marked as read-only with the value "
          "\'" << m_value << "\' was attempted to be "
          "unset.";

  m_what = sstr.str();
}

unset_on_read_only_value_exception
::~unset_on_read_only_value_exception() throw()
{
}

bool
does_not_begin_with(config::key_t const& key, config::key_t const& name)
{
  static config::key_t const global_start = config::global_value + config::block_sep;

  return (!boost::starts_with(key, name + config::block_sep) &&
          !boost::starts_with(key, global_start));
}

config::key_t
strip_block_name(config::key_t const& key)
{
  size_t const pos = key.find(config::block_sep);

  if (pos == config::key_t::npos)
  {
    return key;
  }

  return key.substr(pos + 1);
}

}
<commit_msg>Fix the message for set_on_ro exceptions<commit_after>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "config.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/none.hpp>

#include <algorithm>
#include <sstream>

/**
 * \file config.cxx
 *
 * \brief Implementation of \link vistk::config configuration\endlink in the pipeline.
 */

namespace vistk
{

config::key_t const config::block_sep = key_t(":");
config::key_t const config::global_value = key_t("_global");

static bool does_not_begin_with(config::key_t const& key, config::key_t const& name);
static config::key_t strip_block_name(config::key_t const& key);

config_t
config
::empty_config(key_t const& name)
{
  return config_t(new config(name, config_t()));
}

config
::~config()
{
}

config_t
config
::subblock(key_t const& key) const
{
  config_t conf = empty_config(key);

  BOOST_FOREACH (key_t const& key_name, available_values())
  {
    if (does_not_begin_with(key_name, key))
    {
      continue;
    }

    key_t const stripped_key_name = strip_block_name(key_name);

    conf->set_value(stripped_key_name, get_value(key_name));
  }

  return conf;
}

config_t
config
::subblock_view(key_t const& key)
{
  return config_t(new config(key, shared_from_this()));
}

void
config
::set_value(key_t const& key, value_t const& value)
{
  if (m_parent)
  {
    m_parent->set_value(m_name + block_sep + key, value);
  }
  else
  {
    if (is_read_only(key))
    {
      throw set_on_read_only_value_exception(key, get_value<value_t>(key, value_t()), value);
    }

    m_store[key] = value;
  }
}

void
config
::unset_value(key_t const& key)
{
  if (m_parent)
  {
    m_parent->unset_value(m_name + block_sep + key);
  }
  else
  {
    if (is_read_only(key))
    {
      throw unset_on_read_only_value_exception(key, get_value<value_t>(key, value_t()));
    }

    m_store.erase(key);
  }
}

bool
config
::is_read_only(key_t const& key) const
{
  ro_list_t::iterator i = m_ro_list.find(key);

  return (i != m_ro_list.end());
}

void
config
::mark_read_only(key_t const& key)
{
  m_ro_list.insert(key);
}

void
config
::merge_config(config_t conf)
{
  BOOST_FOREACH (store_t::value_type const& value, conf->m_store)
  {
    set_value(value.first, value.second);
  }
}

config::keys_t
config
::available_values() const
{
  keys_t keys;

  if (m_parent)
  {
    keys = m_parent->available_values();

    keys_t::iterator const i = std::remove_if(keys.begin(), keys.end(), boost::bind(does_not_begin_with, _1, m_name));

    keys.erase(i, keys.end());

    std::for_each(keys.begin(), keys.end(), strip_block_name);
  }
  else
  {
    BOOST_FOREACH (store_t::value_type const& value, m_store)
    {
      keys.push_back(value.first);
    }
  }

  return keys;
}

bool
config
::has_value(key_t const& key) const
{
  if (m_parent)
  {
    return m_parent->has_value(m_name + block_sep + key);
  }

  return (m_store.find(key) != m_store.end());
}

config
::config(key_t const& name, config_t parent)
  : m_parent(parent)
  , m_name(name)
  , m_store()
{
}

boost::optional<config::value_t>
config
::find_value(key_t const& key) const
{
  if (!has_value(key))
  {
    return boost::none;
  }

  return get_value(key);
}

config::value_t
config
::get_value(key_t const& key) const
{
  if (m_parent)
  {
    return m_parent->get_value(m_name + block_sep + key);
  }

  store_t::const_iterator i = m_store.find(key);

  if (i == m_store.end())
  {
    return value_t();
  }

  return i->second;
}

bad_configuration_cast
::bad_configuration_cast(char const* reason) throw()
  : configuration_exception()
{
  m_what = reason;
}

bad_configuration_cast
::~bad_configuration_cast() throw()
{
}

no_such_configuration_value_exception
::no_such_configuration_value_exception(config::key_t const& key) throw()
  : configuration_exception()
  , m_key(key)
{
  std::ostringstream sstr;

  sstr << "There is no configuration value with the key "
          "\'" << m_key << "\'.";

  m_what = sstr.str();
}

no_such_configuration_value_exception
::~no_such_configuration_value_exception() throw()
{
}

bad_configuration_cast_exception
::bad_configuration_cast_exception(config::key_t const& key, config::value_t const& value, char const* type, char const* reason) throw()
  : configuration_exception()
  , m_key(key)
  , m_value(value)
  , m_type(type)
  , m_reason(reason)
{
  std::ostringstream sstr;

  sstr << "Failed to cast key \'" << m_key << "\' "
          "with value \'" << m_value << "\' as "
          "a \'" << m_type << "\': " << m_reason << ".";

  m_what = sstr.str();
}

bad_configuration_cast_exception
::~bad_configuration_cast_exception() throw()
{
}

set_on_read_only_value_exception
::set_on_read_only_value_exception(config::key_t const& key, config::value_t const& value, config::value_t const& new_value) throw()
  : configuration_exception()
  , m_key(key)
  , m_value(value)
  , m_new_value(new_value)
{
  std::ostringstream sstr;

  sstr << "The key \'" << m_key << "\' "
          "was marked as read-only with the value "
          "\'" << m_value << "\' was attempted to be "
          "set to \'" << m_new_value << "\'.";

  m_what = sstr.str();
}

set_on_read_only_value_exception
::~set_on_read_only_value_exception() throw()
{
}

unset_on_read_only_value_exception
::unset_on_read_only_value_exception(config::key_t const& key, config::value_t const& value) throw()
  : configuration_exception()
  , m_key(key)
  , m_value(value)
{
  std::ostringstream sstr;

  sstr << "The key \'" << m_key << "\' "
          "was marked as read-only with the value "
          "\'" << m_value << "\' was attempted to be "
          "unset.";

  m_what = sstr.str();
}

unset_on_read_only_value_exception
::~unset_on_read_only_value_exception() throw()
{
}

bool
does_not_begin_with(config::key_t const& key, config::key_t const& name)
{
  static config::key_t const global_start = config::global_value + config::block_sep;

  return (!boost::starts_with(key, name + config::block_sep) &&
          !boost::starts_with(key, global_start));
}

config::key_t
strip_block_name(config::key_t const& key)
{
  size_t const pos = key.find(config::block_sep);

  if (pos == config::key_t::npos)
  {
    return key;
  }

  return key.substr(pos + 1);
}

}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "environment.h"

#include <QtCore/QDir>
#include <QtCore/QProcess>
#include <QtCore/QString>

namespace Utils {

QList<EnvironmentItem> EnvironmentItem::fromStringList(const QStringList &list)
{
    QList<EnvironmentItem> result;
    foreach (const QString &string, list) {
        int pos = string.indexOf(QLatin1Char('='));
        if (pos == -1) {
            EnvironmentItem item(string, QString());
            item.unset = true;
            result.append(item);
        } else {
            EnvironmentItem item(string.left(pos), string.mid(pos+1));
            result.append(item);
        }
    }
    return result;
}

QStringList EnvironmentItem::toStringList(const QList<EnvironmentItem> &list)
{
    QStringList result;
    foreach (const EnvironmentItem &item, list) {
        if (item.unset)
            result << QString(item.name);
        else
            result << QString(item.name + '=' + item.value);
    }
    return result;
}

Environment::Environment(const QStringList &env)
{
    foreach (const QString &s, env) {
        int i = s.indexOf(QLatin1Char('='));
        if (i >= 0) {
#ifdef Q_OS_WIN
            m_values.insert(s.left(i).toUpper(), s.mid(i+1));
#else
            m_values.insert(s.left(i), s.mid(i+1));
#endif
        }
    }
}

QStringList Environment::toStringList() const
{
    QStringList result;
    const QMap<QString, QString>::const_iterator end = m_values.constEnd();
    for (QMap<QString, QString>::const_iterator it = m_values.constBegin(); it != end; ++it) {
        QString entry = it.key();
        entry += QLatin1Char('=');
        entry += it.value();
        result.push_back(entry);
    }
    return result;
}

void Environment::set(const QString &key, const QString &value)
{
#ifdef Q_OS_WIN
    QString _key = key.toUpper();
#else
    const QString &_key = key;
#endif
    m_values.insert(_key, value);
}

void Environment::unset(const QString &key)
{
#ifdef Q_OS_WIN
    QString _key = key.toUpper();
#else
    const QString &_key = key;
#endif
    m_values.remove(_key);
}

void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep)
{
#ifdef Q_OS_WIN
    QString _key = key.toUpper();
#else
    const QString &_key = key;
#endif
    QMap<QString, QString>::iterator it = m_values.find(key);
    if (it == m_values.end()) {
        m_values.insert(_key, value);
    } else {
        // Append unless it is already there
        const QString toAppend = sep + value;
        if (!it.value().endsWith(toAppend))
            it.value().append(toAppend);
    }
}

void Environment::prependOrSet(const QString&key, const QString &value, const QString &sep)
{
#ifdef Q_OS_WIN
    QString _key = key.toUpper();
#else
    const QString &_key = key;
#endif
    QMap<QString, QString>::iterator it = m_values.find(key);
    if (it == m_values.end()) {
        m_values.insert(_key, value);
    } else {
        // Prepend unless it is already there
        const QString toPrepend = value + sep;
        if (!it.value().startsWith(toPrepend))
            it.value().prepend(toPrepend);
    }
}

void Environment::appendOrSetPath(const QString &value)
{
#ifdef Q_OS_WIN
    const QChar sep = QLatin1Char(';');
#else
    const QChar sep = QLatin1Char(':');
#endif
    appendOrSet(QLatin1String("PATH"), QDir::toNativeSeparators(value), QString(sep));
}

void Environment::prependOrSetPath(const QString &value)
{
#ifdef Q_OS_WIN
    const QChar sep = QLatin1Char(';');
#else
    const QChar sep = QLatin1Char(':');
#endif
    prependOrSet(QLatin1String("PATH"), QDir::toNativeSeparators(value), QString(sep));
}

void Environment::prependOrSetLibrarySearchPath(const QString &value)
{
#ifdef Q_OS_MAC
    // we could set DYLD_LIBRARY_PATH on Mac but it is unnecessary in practice
#elif defined(Q_OS_WIN)
    const QChar sep = QLatin1Char(';');
    const QLatin1String path("PATH");
    prependOrSet(path, QDir::toNativeSeparators(value), QString(sep));
#elif defined(Q_OS_UNIX)
    const QChar sep = QLatin1Char(':');
    const QLatin1String path("LD_LIBRARY_PATH");
    prependOrSet(path, QDir::toNativeSeparators(value), QString(sep));
#endif
}

Environment Environment::systemEnvironment()
{
    return Environment(QProcess::systemEnvironment());
}

void Environment::clear()
{
    m_values.clear();
}

QString Environment::searchInPath(const QString &executable,
                                  const QStringList &additionalDirs) const
{
    QStringList execs;
    execs << executable;
#ifdef Q_OS_WIN
    // Check all the executable extensions on windows:
    QStringList extensions = value(QLatin1String("PATHEXT")).split(QLatin1Char(';'));

    // .exe.bat is legal (and run when starting new.exe), so always go through the complete list once:
    foreach (const QString &ext, extensions)
        execs << executable + ext.toLower();
#endif
    return searchInPath(execs, additionalDirs);
}

QString Environment::searchInPath(const QStringList &executables,
                                  const QStringList &additionalDirs) const
{
    const QChar slash = QLatin1Char('/');
    foreach (const QString &executable, executables) {
        QString exec = QDir::cleanPath(expandVariables(executable));

        if (exec.isEmpty())
            continue;

        QFileInfo baseFi(exec);
        if (baseFi.isAbsolute() && baseFi.exists())
            return exec;

        // Check in directories:
        foreach (const QString &dir, additionalDirs) {
            if (dir.isEmpty())
                continue;
            QFileInfo fi(dir + QLatin1Char('/') + exec);
            if (fi.isFile() && fi.isExecutable())
                return fi.absoluteFilePath();
        }

        // Check in path:
        if (exec.indexOf(slash) != -1)
            continue;
        foreach (const QString &p, path()) {
            QString fp = p;
            fp += slash;
            fp += exec;
            const QFileInfo fi(fp);
            if (fi.exists() && fi.isExecutable() && !fi.isDir())
                return fi.absoluteFilePath();
        }
    }
    return QString();
}

QStringList Environment::path() const
{
#ifdef Q_OS_WIN
    const QChar sep = QLatin1Char(';');
#else
    const QChar sep = QLatin1Char(':');
#endif
    return m_values.value(QLatin1String("PATH")).split(sep, QString::SkipEmptyParts);
}

QString Environment::value(const QString &key) const
{
    return m_values.value(key);
}

QString Environment::key(Environment::const_iterator it) const
{
    return it.key();
}

QString Environment::value(Environment::const_iterator it) const
{
    return it.value();
}

Environment::const_iterator Environment::constBegin() const
{
    return m_values.constBegin();
}

Environment::const_iterator Environment::constEnd() const
{
    return m_values.constEnd();
}

Environment::const_iterator Environment::constFind(const QString &name) const
{
    QMap<QString, QString>::const_iterator it = m_values.constFind(name);
    if (it == m_values.constEnd())
        return constEnd();
    else
        return it;
}

int Environment::size() const
{
    return m_values.size();
}

void Environment::modify(const QList<EnvironmentItem> & list)
{
    Environment resultEnvironment = *this;
    foreach (const EnvironmentItem &item, list) {
        if (item.unset) {
            resultEnvironment.unset(item.name);
        } else {
            // TODO use variable expansion
            QString value = item.value;
            for (int i=0; i < value.size(); ++i) {
                if (value.at(i) == QLatin1Char('$')) {
                    if ((i + 1) < value.size()) {
                        const QChar &c = value.at(i+1);
                        int end = -1;
                        if (c == '(')
                            end = value.indexOf(')', i);
                        else if (c == '{')
                            end = value.indexOf('}', i);
                        if (end != -1) {
                            const QString &name = value.mid(i+2, end-i-2);
                            Environment::const_iterator it = constFind(name);
                            if (it != constEnd())
                                value.replace(i, end-i+1, it.value());
                        }
                    }
                }
            }
            resultEnvironment.set(item.name, value);
        }
    }
    *this = resultEnvironment;
}

QList<EnvironmentItem> Environment::diff(const Environment &other) const
{
    QMap<QString, QString>::const_iterator thisIt = constBegin();
    QMap<QString, QString>::const_iterator otherIt = other.constBegin();

    QList<EnvironmentItem> result;
    while (thisIt != constEnd() || otherIt != other.constEnd()) {
        if (thisIt == constEnd()) {
            result.append(Utils::EnvironmentItem(otherIt.key(), otherIt.value()));
            ++otherIt;
        } else if (otherIt == constEnd()) {
            Utils::EnvironmentItem item(thisIt.key(), QString());
            item.unset = true;
            result.append(item);
            ++thisIt;
        } else if (thisIt.key() < otherIt.key()) {
            Utils::EnvironmentItem item(thisIt.key(), QString());
            item.unset = true;
            result.append(item);
            ++thisIt;
        } else if (thisIt.key() > otherIt.key()) {
            result.append(Utils::EnvironmentItem(otherIt.key(), otherIt.value()));
            ++otherIt;
        } else {
            result.append(Utils::EnvironmentItem(otherIt.key(), otherIt.value()));
            ++otherIt;
            ++thisIt;
        }
    }
    return result;
}

bool Environment::hasKey(const QString &key)
{
    return m_values.contains(key);
}

bool Environment::operator!=(const Environment &other) const
{
    return !(*this == other);
}

bool Environment::operator==(const Environment &other) const
{
    return m_values == other.m_values;
}

/** Expand environment variables in a string.
 *
 * Environment variables are accepted in the following forms:
 * $SOMEVAR, ${SOMEVAR} on Unix and %SOMEVAR% on Windows.
 * No escapes and quoting are supported.
 * If a variable is not found, it is not substituted.
 */
QString Environment::expandVariables(const QString &input) const
{
    QString result = input;

#ifdef Q_OS_WIN
    for (int vStart = -1, i = 0; i < result.length(); ) {
        if (result.at(i++) == QLatin1Char('%')) {
            if (vStart > 0) {
                const_iterator it = m_values.constFind(result.mid(vStart, i - vStart - 1).toUpper());
                if (it != m_values.constEnd()) {
                    result.replace(vStart - 1, i - vStart + 1, *it);
                    i = vStart - 1 + it->length();
                    vStart = -1;
                } else {
                    vStart = i;
                }
            } else {
                vStart = i;
            }
        }
    }
#else
    enum { BASE, OPTIONALVARIABLEBRACE, VARIABLE, BRACEDVARIABLE } state = BASE;
    int vStart = -1;

    for (int i = 0; i < result.length();) {
        QChar c = result.at(i++);
        if (state == BASE) {
            if (c == QLatin1Char('$'))
                state = OPTIONALVARIABLEBRACE;
        } else if (state == OPTIONALVARIABLEBRACE) {
            if (c == QLatin1Char('{')) {
                state = BRACEDVARIABLE;
                vStart = i;
            } else if (c.isLetterOrNumber() || c == QLatin1Char('_')) {
                state = VARIABLE;
                vStart = i - 1;
            } else {
                state = BASE;
            }
        } else if (state == BRACEDVARIABLE) {
            if (c == QLatin1Char('}')) {
                const_iterator it = m_values.constFind(result.mid(vStart, i - 1 - vStart));
                if (it != constEnd()) {
                    result.replace(vStart - 2, i - vStart + 2, *it);
                    i = vStart - 2 + it->length();
                }
                state = BASE;
            }
        } else if (state == VARIABLE) {
            if (!c.isLetterOrNumber() && c != QLatin1Char('_')) {
                const_iterator it = m_values.constFind(result.mid(vStart, i - vStart - 1));
                if (it != constEnd()) {
                    result.replace(vStart - 1, i - vStart, *it);
                    i = vStart - 1 + it->length();
                }
                state = BASE;
            }
        }
    }
    if (state == VARIABLE) {
        const_iterator it = m_values.constFind(result.mid(vStart));
        if (it != constEnd())
            result.replace(vStart - 1, result.length() - vStart + 1, *it);
    }
#endif
    return result;
}

QStringList Environment::expandVariables(const QStringList &variables) const
{
    QStringList results;
    foreach (const QString &i, variables)
        results << expandVariables(i);
    return results;
}

} // namespace Utils
<commit_msg>Mac: Fix compilation warning<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "environment.h"

#include <QtCore/QDir>
#include <QtCore/QProcess>
#include <QtCore/QString>

namespace Utils {

QList<EnvironmentItem> EnvironmentItem::fromStringList(const QStringList &list)
{
    QList<EnvironmentItem> result;
    foreach (const QString &string, list) {
        int pos = string.indexOf(QLatin1Char('='));
        if (pos == -1) {
            EnvironmentItem item(string, QString());
            item.unset = true;
            result.append(item);
        } else {
            EnvironmentItem item(string.left(pos), string.mid(pos+1));
            result.append(item);
        }
    }
    return result;
}

QStringList EnvironmentItem::toStringList(const QList<EnvironmentItem> &list)
{
    QStringList result;
    foreach (const EnvironmentItem &item, list) {
        if (item.unset)
            result << QString(item.name);
        else
            result << QString(item.name + '=' + item.value);
    }
    return result;
}

Environment::Environment(const QStringList &env)
{
    foreach (const QString &s, env) {
        int i = s.indexOf(QLatin1Char('='));
        if (i >= 0) {
#ifdef Q_OS_WIN
            m_values.insert(s.left(i).toUpper(), s.mid(i+1));
#else
            m_values.insert(s.left(i), s.mid(i+1));
#endif
        }
    }
}

QStringList Environment::toStringList() const
{
    QStringList result;
    const QMap<QString, QString>::const_iterator end = m_values.constEnd();
    for (QMap<QString, QString>::const_iterator it = m_values.constBegin(); it != end; ++it) {
        QString entry = it.key();
        entry += QLatin1Char('=');
        entry += it.value();
        result.push_back(entry);
    }
    return result;
}

void Environment::set(const QString &key, const QString &value)
{
#ifdef Q_OS_WIN
    QString _key = key.toUpper();
#else
    const QString &_key = key;
#endif
    m_values.insert(_key, value);
}

void Environment::unset(const QString &key)
{
#ifdef Q_OS_WIN
    QString _key = key.toUpper();
#else
    const QString &_key = key;
#endif
    m_values.remove(_key);
}

void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep)
{
#ifdef Q_OS_WIN
    QString _key = key.toUpper();
#else
    const QString &_key = key;
#endif
    QMap<QString, QString>::iterator it = m_values.find(key);
    if (it == m_values.end()) {
        m_values.insert(_key, value);
    } else {
        // Append unless it is already there
        const QString toAppend = sep + value;
        if (!it.value().endsWith(toAppend))
            it.value().append(toAppend);
    }
}

void Environment::prependOrSet(const QString&key, const QString &value, const QString &sep)
{
#ifdef Q_OS_WIN
    QString _key = key.toUpper();
#else
    const QString &_key = key;
#endif
    QMap<QString, QString>::iterator it = m_values.find(key);
    if (it == m_values.end()) {
        m_values.insert(_key, value);
    } else {
        // Prepend unless it is already there
        const QString toPrepend = value + sep;
        if (!it.value().startsWith(toPrepend))
            it.value().prepend(toPrepend);
    }
}

void Environment::appendOrSetPath(const QString &value)
{
#ifdef Q_OS_WIN
    const QChar sep = QLatin1Char(';');
#else
    const QChar sep = QLatin1Char(':');
#endif
    appendOrSet(QLatin1String("PATH"), QDir::toNativeSeparators(value), QString(sep));
}

void Environment::prependOrSetPath(const QString &value)
{
#ifdef Q_OS_WIN
    const QChar sep = QLatin1Char(';');
#else
    const QChar sep = QLatin1Char(':');
#endif
    prependOrSet(QLatin1String("PATH"), QDir::toNativeSeparators(value), QString(sep));
}

void Environment::prependOrSetLibrarySearchPath(const QString &value)
{
#ifdef Q_OS_MAC
    Q_UNUSED(value);
    // we could set DYLD_LIBRARY_PATH on Mac but it is unnecessary in practice
#elif defined(Q_OS_WIN)
    const QChar sep = QLatin1Char(';');
    const QLatin1String path("PATH");
    prependOrSet(path, QDir::toNativeSeparators(value), QString(sep));
#elif defined(Q_OS_UNIX)
    const QChar sep = QLatin1Char(':');
    const QLatin1String path("LD_LIBRARY_PATH");
    prependOrSet(path, QDir::toNativeSeparators(value), QString(sep));
#endif
}

Environment Environment::systemEnvironment()
{
    return Environment(QProcess::systemEnvironment());
}

void Environment::clear()
{
    m_values.clear();
}

QString Environment::searchInPath(const QString &executable,
                                  const QStringList &additionalDirs) const
{
    QStringList execs;
    execs << executable;
#ifdef Q_OS_WIN
    // Check all the executable extensions on windows:
    QStringList extensions = value(QLatin1String("PATHEXT")).split(QLatin1Char(';'));

    // .exe.bat is legal (and run when starting new.exe), so always go through the complete list once:
    foreach (const QString &ext, extensions)
        execs << executable + ext.toLower();
#endif
    return searchInPath(execs, additionalDirs);
}

QString Environment::searchInPath(const QStringList &executables,
                                  const QStringList &additionalDirs) const
{
    const QChar slash = QLatin1Char('/');
    foreach (const QString &executable, executables) {
        QString exec = QDir::cleanPath(expandVariables(executable));

        if (exec.isEmpty())
            continue;

        QFileInfo baseFi(exec);
        if (baseFi.isAbsolute() && baseFi.exists())
            return exec;

        // Check in directories:
        foreach (const QString &dir, additionalDirs) {
            if (dir.isEmpty())
                continue;
            QFileInfo fi(dir + QLatin1Char('/') + exec);
            if (fi.isFile() && fi.isExecutable())
                return fi.absoluteFilePath();
        }

        // Check in path:
        if (exec.indexOf(slash) != -1)
            continue;
        foreach (const QString &p, path()) {
            QString fp = p;
            fp += slash;
            fp += exec;
            const QFileInfo fi(fp);
            if (fi.exists() && fi.isExecutable() && !fi.isDir())
                return fi.absoluteFilePath();
        }
    }
    return QString();
}

QStringList Environment::path() const
{
#ifdef Q_OS_WIN
    const QChar sep = QLatin1Char(';');
#else
    const QChar sep = QLatin1Char(':');
#endif
    return m_values.value(QLatin1String("PATH")).split(sep, QString::SkipEmptyParts);
}

QString Environment::value(const QString &key) const
{
    return m_values.value(key);
}

QString Environment::key(Environment::const_iterator it) const
{
    return it.key();
}

QString Environment::value(Environment::const_iterator it) const
{
    return it.value();
}

Environment::const_iterator Environment::constBegin() const
{
    return m_values.constBegin();
}

Environment::const_iterator Environment::constEnd() const
{
    return m_values.constEnd();
}

Environment::const_iterator Environment::constFind(const QString &name) const
{
    QMap<QString, QString>::const_iterator it = m_values.constFind(name);
    if (it == m_values.constEnd())
        return constEnd();
    else
        return it;
}

int Environment::size() const
{
    return m_values.size();
}

void Environment::modify(const QList<EnvironmentItem> & list)
{
    Environment resultEnvironment = *this;
    foreach (const EnvironmentItem &item, list) {
        if (item.unset) {
            resultEnvironment.unset(item.name);
        } else {
            // TODO use variable expansion
            QString value = item.value;
            for (int i=0; i < value.size(); ++i) {
                if (value.at(i) == QLatin1Char('$')) {
                    if ((i + 1) < value.size()) {
                        const QChar &c = value.at(i+1);
                        int end = -1;
                        if (c == '(')
                            end = value.indexOf(')', i);
                        else if (c == '{')
                            end = value.indexOf('}', i);
                        if (end != -1) {
                            const QString &name = value.mid(i+2, end-i-2);
                            Environment::const_iterator it = constFind(name);
                            if (it != constEnd())
                                value.replace(i, end-i+1, it.value());
                        }
                    }
                }
            }
            resultEnvironment.set(item.name, value);
        }
    }
    *this = resultEnvironment;
}

QList<EnvironmentItem> Environment::diff(const Environment &other) const
{
    QMap<QString, QString>::const_iterator thisIt = constBegin();
    QMap<QString, QString>::const_iterator otherIt = other.constBegin();

    QList<EnvironmentItem> result;
    while (thisIt != constEnd() || otherIt != other.constEnd()) {
        if (thisIt == constEnd()) {
            result.append(Utils::EnvironmentItem(otherIt.key(), otherIt.value()));
            ++otherIt;
        } else if (otherIt == constEnd()) {
            Utils::EnvironmentItem item(thisIt.key(), QString());
            item.unset = true;
            result.append(item);
            ++thisIt;
        } else if (thisIt.key() < otherIt.key()) {
            Utils::EnvironmentItem item(thisIt.key(), QString());
            item.unset = true;
            result.append(item);
            ++thisIt;
        } else if (thisIt.key() > otherIt.key()) {
            result.append(Utils::EnvironmentItem(otherIt.key(), otherIt.value()));
            ++otherIt;
        } else {
            result.append(Utils::EnvironmentItem(otherIt.key(), otherIt.value()));
            ++otherIt;
            ++thisIt;
        }
    }
    return result;
}

bool Environment::hasKey(const QString &key)
{
    return m_values.contains(key);
}

bool Environment::operator!=(const Environment &other) const
{
    return !(*this == other);
}

bool Environment::operator==(const Environment &other) const
{
    return m_values == other.m_values;
}

/** Expand environment variables in a string.
 *
 * Environment variables are accepted in the following forms:
 * $SOMEVAR, ${SOMEVAR} on Unix and %SOMEVAR% on Windows.
 * No escapes and quoting are supported.
 * If a variable is not found, it is not substituted.
 */
QString Environment::expandVariables(const QString &input) const
{
    QString result = input;

#ifdef Q_OS_WIN
    for (int vStart = -1, i = 0; i < result.length(); ) {
        if (result.at(i++) == QLatin1Char('%')) {
            if (vStart > 0) {
                const_iterator it = m_values.constFind(result.mid(vStart, i - vStart - 1).toUpper());
                if (it != m_values.constEnd()) {
                    result.replace(vStart - 1, i - vStart + 1, *it);
                    i = vStart - 1 + it->length();
                    vStart = -1;
                } else {
                    vStart = i;
                }
            } else {
                vStart = i;
            }
        }
    }
#else
    enum { BASE, OPTIONALVARIABLEBRACE, VARIABLE, BRACEDVARIABLE } state = BASE;
    int vStart = -1;

    for (int i = 0; i < result.length();) {
        QChar c = result.at(i++);
        if (state == BASE) {
            if (c == QLatin1Char('$'))
                state = OPTIONALVARIABLEBRACE;
        } else if (state == OPTIONALVARIABLEBRACE) {
            if (c == QLatin1Char('{')) {
                state = BRACEDVARIABLE;
                vStart = i;
            } else if (c.isLetterOrNumber() || c == QLatin1Char('_')) {
                state = VARIABLE;
                vStart = i - 1;
            } else {
                state = BASE;
            }
        } else if (state == BRACEDVARIABLE) {
            if (c == QLatin1Char('}')) {
                const_iterator it = m_values.constFind(result.mid(vStart, i - 1 - vStart));
                if (it != constEnd()) {
                    result.replace(vStart - 2, i - vStart + 2, *it);
                    i = vStart - 2 + it->length();
                }
                state = BASE;
            }
        } else if (state == VARIABLE) {
            if (!c.isLetterOrNumber() && c != QLatin1Char('_')) {
                const_iterator it = m_values.constFind(result.mid(vStart, i - vStart - 1));
                if (it != constEnd()) {
                    result.replace(vStart - 1, i - vStart, *it);
                    i = vStart - 1 + it->length();
                }
                state = BASE;
            }
        }
    }
    if (state == VARIABLE) {
        const_iterator it = m_values.constFind(result.mid(vStart));
        if (it != constEnd())
            result.replace(vStart - 1, result.length() - vStart + 1, *it);
    }
#endif
    return result;
}

QStringList Environment::expandVariables(const QStringList &variables) const
{
    QStringList results;
    foreach (const QString &i, variables)
        results << expandVariables(i);
    return results;
}

} // namespace Utils
<|endoftext|>